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
|
@@ -9,14 +9,37 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import hashlib
|
|
11
11
|
import json
|
|
12
|
+
import re
|
|
12
13
|
from typing import Any
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
PUBLIC_PROFILE_SCHEMA = "translate-native.commercial-capabilities.
|
|
16
|
+
PUBLIC_PROFILE_SCHEMA = "translate-native.commercial-capabilities.v15"
|
|
17
|
+
REVIEW_EVIDENCE_CAPABILITIES_SCHEMA = (
|
|
18
|
+
"translate-native.commercial-review-evidence-capabilities.v2"
|
|
19
|
+
)
|
|
16
20
|
REVIEW_SUMMARY_CAPABILITIES_SCHEMA = (
|
|
17
|
-
"translate-native.commercial-review-summary-capabilities.
|
|
21
|
+
"translate-native.commercial-review-summary-capabilities.v7"
|
|
22
|
+
)
|
|
23
|
+
REVIEW_SUMMARY_SCHEMA = "translate-native.commercial-review-summary.v6"
|
|
24
|
+
REVIEW_ROUTING_CAPABILITIES_SCHEMA = (
|
|
25
|
+
"translate-native.commercial-review-routing-capabilities.v1"
|
|
26
|
+
)
|
|
27
|
+
REVIEW_ROUTING_SCHEMA = "translate-native.commercial-review-routing.v2"
|
|
28
|
+
EVIDENCE_BINDING_SCHEMA = "translate-native.commercial-review-evidence-binding.v5"
|
|
29
|
+
REVIEW_RESOLUTION_CAPABILITIES_SCHEMA = (
|
|
30
|
+
"translate-native.commercial-review-resolution-capabilities.v4"
|
|
31
|
+
)
|
|
32
|
+
REVIEW_RESOLUTION_SCHEMA = "translate-native.commercial-review-resolution.v4"
|
|
33
|
+
COMMERCIAL_LOCALE_PROFILE_SCHEMA = (
|
|
34
|
+
"translate-native.commercial-locale-quality-profile.v2"
|
|
18
35
|
)
|
|
19
|
-
|
|
36
|
+
COMMERCIAL_RENDERING_REFERENCE_SCHEMA = (
|
|
37
|
+
"translate-native.commercial-rendering-reference.v1"
|
|
38
|
+
)
|
|
39
|
+
TARGET_LOCALE = re.compile(
|
|
40
|
+
r"^[a-z]{2,3}(?:-[A-Z][a-z]{3})?-[A-Z]{2}$"
|
|
41
|
+
)
|
|
42
|
+
PROFILE_VERSION = re.compile(r"^[A-Za-z0-9_.:-]{1,256}$")
|
|
20
43
|
|
|
21
44
|
DIMENSIONS = {
|
|
22
45
|
"amount_currency": "Amounts, currency identity, units and price-to-product association; no conversion or rounding.",
|
|
@@ -38,6 +61,44 @@ def _canonical_json(value: Any) -> bytes:
|
|
|
38
61
|
).encode("utf-8")
|
|
39
62
|
|
|
40
63
|
|
|
64
|
+
def _text_sha256(value: str) -> str:
|
|
65
|
+
return hashlib.sha256(value.encode("utf-8")).hexdigest()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def evidence_sha256(
|
|
69
|
+
value: Any,
|
|
70
|
+
source: str,
|
|
71
|
+
target: str,
|
|
72
|
+
profile: str,
|
|
73
|
+
*,
|
|
74
|
+
target_locale: str,
|
|
75
|
+
commercial_quality_profile_version: str,
|
|
76
|
+
commercial_quality_profile_sha256: str,
|
|
77
|
+
) -> str:
|
|
78
|
+
"""Bind evidence to exact texts, locale, and commercial quality generation."""
|
|
79
|
+
review_evidence_contract_sha256 = public_review_evidence_contract(
|
|
80
|
+
profile,
|
|
81
|
+
)["sha256"]
|
|
82
|
+
binding = {
|
|
83
|
+
"schema": EVIDENCE_BINDING_SCHEMA,
|
|
84
|
+
"profile": profile,
|
|
85
|
+
"review_evidence_contract_sha256": (
|
|
86
|
+
review_evidence_contract_sha256
|
|
87
|
+
),
|
|
88
|
+
"target_locale": target_locale,
|
|
89
|
+
"commercial_quality_profile_version": (
|
|
90
|
+
commercial_quality_profile_version
|
|
91
|
+
),
|
|
92
|
+
"commercial_quality_profile_sha256": (
|
|
93
|
+
commercial_quality_profile_sha256
|
|
94
|
+
),
|
|
95
|
+
"source_sha256": _text_sha256(source),
|
|
96
|
+
"target_sha256": _text_sha256(target),
|
|
97
|
+
"evidence": value,
|
|
98
|
+
}
|
|
99
|
+
return hashlib.sha256(_canonical_json(binding)).hexdigest()
|
|
100
|
+
|
|
101
|
+
|
|
41
102
|
def public_review_summary_contract(profile: str) -> dict[str, Any]:
|
|
42
103
|
"""Return the exact content-free summary contract external adapters consume."""
|
|
43
104
|
body = {
|
|
@@ -46,12 +107,17 @@ def public_review_summary_contract(profile: str) -> dict[str, Any]:
|
|
|
46
107
|
"profile": profile,
|
|
47
108
|
"required_fields": [
|
|
48
109
|
"schema", "profile", "status", "review_required_dimensions",
|
|
49
|
-
"
|
|
110
|
+
"offer_count", "review_required_offers",
|
|
111
|
+
"review_evidence_contract_sha256", "evidence_sha256",
|
|
50
112
|
],
|
|
51
113
|
"statuses": {
|
|
52
|
-
"verified": {
|
|
114
|
+
"verified": {
|
|
115
|
+
"review_required_dimensions": "empty",
|
|
116
|
+
"review_required_offers": "empty",
|
|
117
|
+
},
|
|
53
118
|
"review_required": {
|
|
54
119
|
"review_required_dimensions": "one-or-more",
|
|
120
|
+
"review_required_offers": "zero-or-more",
|
|
55
121
|
"requires_independent_review": True,
|
|
56
122
|
},
|
|
57
123
|
},
|
|
@@ -60,10 +126,51 @@ def public_review_summary_contract(profile: str) -> dict[str, Any]:
|
|
|
60
126
|
"order": list(DIMENSIONS),
|
|
61
127
|
"unique": True,
|
|
62
128
|
},
|
|
129
|
+
"review_required_offers": {
|
|
130
|
+
"item_required_fields": ["dimension", "offer_indexes"],
|
|
131
|
+
"dimension_order": list(DIMENSIONS),
|
|
132
|
+
"dimension_must_be_review_required": True,
|
|
133
|
+
"offer_indexes": {
|
|
134
|
+
"meaning": "zero-based-opaque-offer-registry-position",
|
|
135
|
+
"minimum": 0,
|
|
136
|
+
"maximum_exclusive": 1000,
|
|
137
|
+
"order": "ascending",
|
|
138
|
+
"unique": True,
|
|
139
|
+
},
|
|
140
|
+
"configured_offer_identifiers_published": False,
|
|
141
|
+
},
|
|
142
|
+
"offer_count": {
|
|
143
|
+
"meaning": "opaque-offer-registry-size",
|
|
144
|
+
"minimum": 0,
|
|
145
|
+
"maximum": 1000,
|
|
146
|
+
},
|
|
63
147
|
"evidence_sha256": {
|
|
64
148
|
"algorithm": "sha-256",
|
|
65
149
|
"canonicalization": "utf-8-json-sort-keys-no-insignificant-whitespace",
|
|
66
|
-
"
|
|
150
|
+
"binding_schema": EVIDENCE_BINDING_SCHEMA,
|
|
151
|
+
"binding_fields": [
|
|
152
|
+
"schema", "profile", "review_evidence_contract_sha256",
|
|
153
|
+
"target_locale",
|
|
154
|
+
"commercial_quality_profile_version",
|
|
155
|
+
"commercial_quality_profile_sha256", "source_sha256",
|
|
156
|
+
"target_sha256", "evidence",
|
|
157
|
+
],
|
|
158
|
+
"text_hashing": "exact-utf-8",
|
|
159
|
+
"covers": [
|
|
160
|
+
"commercial-profile",
|
|
161
|
+
"exact-review-evidence-contract",
|
|
162
|
+
"exact-target-locale",
|
|
163
|
+
"commercial-quality-profile-generation",
|
|
164
|
+
"exact-source-sha256",
|
|
165
|
+
"exact-target-sha256",
|
|
166
|
+
"offer-registry-and-proposition-assignment",
|
|
167
|
+
"complete-commercial-review-evidence",
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
"review_evidence_contract_sha256": {
|
|
171
|
+
"algorithm": "sha-256",
|
|
172
|
+
"equals": public_review_evidence_contract(profile)["sha256"],
|
|
173
|
+
"purpose": "reject-stale-or-reinterpreted-private-evidence",
|
|
67
174
|
},
|
|
68
175
|
"content_policy": {
|
|
69
176
|
"source_text": False,
|
|
@@ -81,13 +188,335 @@ def public_review_summary_contract(profile: str) -> dict[str, Any]:
|
|
|
81
188
|
}
|
|
82
189
|
|
|
83
190
|
|
|
191
|
+
def public_review_evidence_contract(profile: str) -> dict[str, Any]:
|
|
192
|
+
"""Return the exact public contract for private commercial evidence."""
|
|
193
|
+
body = {
|
|
194
|
+
"schema": REVIEW_EVIDENCE_CAPABILITIES_SCHEMA,
|
|
195
|
+
"result_schema": profile,
|
|
196
|
+
"profile": profile,
|
|
197
|
+
"required_fields": ["schema", "coverage", "offers", "checks"],
|
|
198
|
+
"coverage": {
|
|
199
|
+
"allowed": ["complete", "uncertain"],
|
|
200
|
+
"complete": "every-proposition-and-offer-association-reviewed",
|
|
201
|
+
"uncertain": "independent-review-required",
|
|
202
|
+
},
|
|
203
|
+
"offer_registry": {
|
|
204
|
+
"field": "offers",
|
|
205
|
+
"max_items": 1000,
|
|
206
|
+
"item_required_fields": [
|
|
207
|
+
"id", "source_spans", "target_spans",
|
|
208
|
+
],
|
|
209
|
+
"identifier": {
|
|
210
|
+
"pattern": PROFILE_VERSION.pattern,
|
|
211
|
+
"unique": True,
|
|
212
|
+
},
|
|
213
|
+
"regions": {
|
|
214
|
+
"fields": ["source_spans", "target_spans"],
|
|
215
|
+
"span_format": (
|
|
216
|
+
"zero-based-unicode-code-points-exclusive-end"
|
|
217
|
+
),
|
|
218
|
+
"non_empty_text": True,
|
|
219
|
+
"ordered": True,
|
|
220
|
+
"overlap": "forbidden-within-and-across-offers",
|
|
221
|
+
"discontiguous": True,
|
|
222
|
+
"at_least_one_side_non_empty": True,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
"checks": {
|
|
226
|
+
"required_dimensions": list(DIMENSIONS),
|
|
227
|
+
"exact_dimension_set": True,
|
|
228
|
+
"max_items_per_dimension": 1000,
|
|
229
|
+
"statuses": [
|
|
230
|
+
"equivalent", "not_present", "changed", "uncertain",
|
|
231
|
+
],
|
|
232
|
+
"status_items": {
|
|
233
|
+
"equivalent": "one-or-more-matched",
|
|
234
|
+
"not_present": "empty",
|
|
235
|
+
"changed": "one-or-more-specific",
|
|
236
|
+
"uncertain": "one-or-more-specific",
|
|
237
|
+
},
|
|
238
|
+
"offer_statuses": {
|
|
239
|
+
"field": "offer_statuses",
|
|
240
|
+
"item_required_fields": ["offer", "status"],
|
|
241
|
+
"coverage": "exactly-one-per-registered-offer",
|
|
242
|
+
"order": "offer-registry-order",
|
|
243
|
+
"statuses": [
|
|
244
|
+
"equivalent", "not_present", "changed", "uncertain",
|
|
245
|
+
],
|
|
246
|
+
"global_status": (
|
|
247
|
+
"changed-then-uncertain-then-equivalent-then-not_present"
|
|
248
|
+
),
|
|
249
|
+
"items_must_match_offer_status": True,
|
|
250
|
+
},
|
|
251
|
+
"item": {
|
|
252
|
+
"required_fields": [
|
|
253
|
+
"offer", "relation", "source_span", "target_span",
|
|
254
|
+
"explanation",
|
|
255
|
+
],
|
|
256
|
+
"offer": "registered-offer-id",
|
|
257
|
+
"relations": ["matched", "source_only", "target_only"],
|
|
258
|
+
"matched_requires": "source-and-target-spans",
|
|
259
|
+
"source_only_requires": "source-span-and-null-target-span",
|
|
260
|
+
"target_only_requires": "null-source-span-and-target-span",
|
|
261
|
+
"span_containment": "inside-named-offer-region",
|
|
262
|
+
"duplicates": "forbidden-per-dimension",
|
|
263
|
+
"explanation": "non-empty-maximum-2000-code-points",
|
|
264
|
+
},
|
|
265
|
+
"offer_assignment": {
|
|
266
|
+
"equivalent": (
|
|
267
|
+
"exactly-one-matched-item-per-registered-offer"
|
|
268
|
+
),
|
|
269
|
+
"other_equivalent_checks_require_equivalent_assignment": True,
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
"trust_boundary": {
|
|
273
|
+
"validates": "structure-offsets-and-verdict-consistency",
|
|
274
|
+
"semantic_truth": False,
|
|
275
|
+
"numeric_regex_semantic_proof": False,
|
|
276
|
+
"unresolved_route": (
|
|
277
|
+
"independent-model-or-qualified-native-domain-review"
|
|
278
|
+
),
|
|
279
|
+
"publication_authority": False,
|
|
280
|
+
},
|
|
281
|
+
"content_policy": {
|
|
282
|
+
"source_text": False,
|
|
283
|
+
"target_text": False,
|
|
284
|
+
"source_spans": False,
|
|
285
|
+
"target_spans": False,
|
|
286
|
+
"reviewer_prose": False,
|
|
287
|
+
"project_prices": False,
|
|
288
|
+
"project_brands": False,
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
**body,
|
|
293
|
+
"sha256": hashlib.sha256(_canonical_json(body)).hexdigest(),
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def public_review_routing_contract(profile: str) -> dict[str, Any]:
|
|
298
|
+
"""Return the exact public contract for private actionable offer routes."""
|
|
299
|
+
body = {
|
|
300
|
+
"schema": REVIEW_ROUTING_CAPABILITIES_SCHEMA,
|
|
301
|
+
"result_schema": REVIEW_ROUTING_SCHEMA,
|
|
302
|
+
"profile": profile,
|
|
303
|
+
"applies_when": {
|
|
304
|
+
"review_summary_status": "review_required",
|
|
305
|
+
"offer_count": "exact-review-summary-offer-count",
|
|
306
|
+
},
|
|
307
|
+
"required_fields": [
|
|
308
|
+
"schema", "profile", "contract_sha256", "offer_count",
|
|
309
|
+
"source_length", "target_length", "offers",
|
|
310
|
+
],
|
|
311
|
+
"text_lengths": {
|
|
312
|
+
"fields": ["source_length", "target_length"],
|
|
313
|
+
"unit": "unicode-code-points",
|
|
314
|
+
"must_equal_complete_texts": True,
|
|
315
|
+
},
|
|
316
|
+
"offers": {
|
|
317
|
+
"coverage": "exactly-one-per-registered-offer",
|
|
318
|
+
"order": "offer-registry-order",
|
|
319
|
+
"item_required_fields": [
|
|
320
|
+
"offer_index", "source_spans", "target_spans",
|
|
321
|
+
],
|
|
322
|
+
"offer_index": {
|
|
323
|
+
"meaning": "zero-based-opaque-offer-registry-position",
|
|
324
|
+
"minimum": 0,
|
|
325
|
+
"maximum_exclusive": 1000,
|
|
326
|
+
"order": "ascending",
|
|
327
|
+
"unique": True,
|
|
328
|
+
},
|
|
329
|
+
"regions": {
|
|
330
|
+
"fields": ["source_spans", "target_spans"],
|
|
331
|
+
"span_format": (
|
|
332
|
+
"zero-based-unicode-code-points-exclusive-end"
|
|
333
|
+
),
|
|
334
|
+
"non_empty_text": True,
|
|
335
|
+
"ordered": True,
|
|
336
|
+
"overlap": "forbidden-within-and-across-offers",
|
|
337
|
+
"discontiguous": True,
|
|
338
|
+
"at_least_one_side_non_empty": True,
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
"trust_boundary": {
|
|
342
|
+
"validates": "shape-offsets-order-count-and-text-lengths",
|
|
343
|
+
"semantic_truth": False,
|
|
344
|
+
"route_values": "private-evidence-and-receipt-boundary-only",
|
|
345
|
+
"public_release_evidence": False,
|
|
346
|
+
"publication_authority": False,
|
|
347
|
+
},
|
|
348
|
+
"content_policy": {
|
|
349
|
+
"configured_offer_identifiers": False,
|
|
350
|
+
"source_text": False,
|
|
351
|
+
"target_text": False,
|
|
352
|
+
"reviewer_prose": False,
|
|
353
|
+
"project_prices": False,
|
|
354
|
+
"project_brands": False,
|
|
355
|
+
},
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
**body,
|
|
359
|
+
"sha256": hashlib.sha256(_canonical_json(body)).hexdigest(),
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def public_review_resolution_contract(profile: str) -> dict[str, Any]:
|
|
364
|
+
"""Return the exact content-free contract for resolving uncertain checks."""
|
|
365
|
+
body = {
|
|
366
|
+
"schema": REVIEW_RESOLUTION_CAPABILITIES_SCHEMA,
|
|
367
|
+
"result_schema": REVIEW_RESOLUTION_SCHEMA,
|
|
368
|
+
"profile": profile,
|
|
369
|
+
"applies_when": {
|
|
370
|
+
"review_summary_status": "review_required",
|
|
371
|
+
"reviewed_dimensions": "exact-ordered-review-summary-dimensions",
|
|
372
|
+
"reviewed_offer_count": "exact-review-summary-offer-count",
|
|
373
|
+
"reviewed_offers": "exact-ordered-review-summary-offer-scope",
|
|
374
|
+
},
|
|
375
|
+
"required_fields": [
|
|
376
|
+
"schema", "profile", "contract_sha256", "status",
|
|
377
|
+
"reviewed_dimensions", "reviewed_offer_count", "reviewed_offers",
|
|
378
|
+
"method", "receipt_sha256",
|
|
379
|
+
"primary_provider", "provider",
|
|
380
|
+
],
|
|
381
|
+
"status": "resolved",
|
|
382
|
+
"methods": {
|
|
383
|
+
"qualified_human": {
|
|
384
|
+
"primary_provider": "required",
|
|
385
|
+
"provider": "null",
|
|
386
|
+
"receipt": "verified-qualified-human-review",
|
|
387
|
+
},
|
|
388
|
+
"independent_model": {
|
|
389
|
+
"primary_provider": "required",
|
|
390
|
+
"provider": "required",
|
|
391
|
+
"provider_id_must_differ_from_primary_provider": True,
|
|
392
|
+
"receipt": "verified-independent-model-review",
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
"provider_identity": {
|
|
396
|
+
"fields": ["id", "model_id", "model_version"],
|
|
397
|
+
"primary_provider": "required",
|
|
398
|
+
"credentials_published": False,
|
|
399
|
+
},
|
|
400
|
+
"reviewed_dimensions": {
|
|
401
|
+
"allowed": list(DIMENSIONS),
|
|
402
|
+
"order": list(DIMENSIONS),
|
|
403
|
+
"unique": True,
|
|
404
|
+
"must_equal_review_summary": True,
|
|
405
|
+
},
|
|
406
|
+
"reviewed_offers": {
|
|
407
|
+
"must_equal_review_summary": True,
|
|
408
|
+
"configured_offer_identifiers_published": False,
|
|
409
|
+
},
|
|
410
|
+
"reviewed_offer_count": {
|
|
411
|
+
"must_equal_review_summary": True,
|
|
412
|
+
},
|
|
413
|
+
"receipt_sha256": {
|
|
414
|
+
"algorithm": "sha-256",
|
|
415
|
+
"covers": "exact-verified-review-receipt",
|
|
416
|
+
"raw_receipt_published": False,
|
|
417
|
+
},
|
|
418
|
+
"content_policy": {
|
|
419
|
+
"source_text": False,
|
|
420
|
+
"target_text": False,
|
|
421
|
+
"raw_receipt": False,
|
|
422
|
+
"reviewer_prose": False,
|
|
423
|
+
"qualified_human_identity": False,
|
|
424
|
+
"project_prices": False,
|
|
425
|
+
"project_brands": False,
|
|
426
|
+
},
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
**body,
|
|
430
|
+
"sha256": hashlib.sha256(_canonical_json(body)).hexdigest(),
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _resolution_provider(value: Any) -> dict[str, str] | None:
|
|
435
|
+
if value is None:
|
|
436
|
+
return None
|
|
437
|
+
if not isinstance(value, dict) or set(value) != {
|
|
438
|
+
"id", "model_id", "model_version",
|
|
439
|
+
}:
|
|
440
|
+
raise CommercialReviewBlocked("review.commercial.resolution_invalid")
|
|
441
|
+
if any(
|
|
442
|
+
not isinstance(value.get(field), str)
|
|
443
|
+
or PROFILE_VERSION.fullmatch(value[field]) is None
|
|
444
|
+
for field in value
|
|
445
|
+
):
|
|
446
|
+
raise CommercialReviewBlocked("review.commercial.resolution_invalid")
|
|
447
|
+
return json.loads(_canonical_json(value))
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def validate_review_resolution(
|
|
451
|
+
value: Any,
|
|
452
|
+
summary: Any,
|
|
453
|
+
profile: str,
|
|
454
|
+
) -> dict[str, Any]:
|
|
455
|
+
"""Validate exact review-resolution routing without trusting reviewer prose."""
|
|
456
|
+
summary = validate_summary(summary, profile, review_required=True)
|
|
457
|
+
contract = public_review_resolution_contract(profile)
|
|
458
|
+
if (
|
|
459
|
+
not isinstance(value, dict)
|
|
460
|
+
or set(value) != {
|
|
461
|
+
"schema", "profile", "contract_sha256", "status",
|
|
462
|
+
"reviewed_dimensions", "reviewed_offer_count", "reviewed_offers",
|
|
463
|
+
"method", "receipt_sha256",
|
|
464
|
+
"primary_provider", "provider",
|
|
465
|
+
}
|
|
466
|
+
or value.get("schema") != REVIEW_RESOLUTION_SCHEMA
|
|
467
|
+
or value.get("profile") != profile
|
|
468
|
+
or value.get("contract_sha256") != contract["sha256"]
|
|
469
|
+
or value.get("status") != "resolved"
|
|
470
|
+
or value.get("reviewed_dimensions")
|
|
471
|
+
!= summary["review_required_dimensions"]
|
|
472
|
+
or value.get("reviewed_offer_count") != summary["offer_count"]
|
|
473
|
+
or value.get("reviewed_offers")
|
|
474
|
+
!= summary["review_required_offers"]
|
|
475
|
+
or value.get("method") not in {
|
|
476
|
+
"qualified_human", "independent_model",
|
|
477
|
+
}
|
|
478
|
+
or not isinstance(value.get("receipt_sha256"), str)
|
|
479
|
+
or len(value["receipt_sha256"]) != 64
|
|
480
|
+
or any(
|
|
481
|
+
character not in "0123456789abcdef"
|
|
482
|
+
for character in value["receipt_sha256"]
|
|
483
|
+
)
|
|
484
|
+
):
|
|
485
|
+
raise CommercialReviewBlocked("review.commercial.resolution_invalid")
|
|
486
|
+
primary_provider = _resolution_provider(value.get("primary_provider"))
|
|
487
|
+
provider = _resolution_provider(value.get("provider"))
|
|
488
|
+
if primary_provider is None or (
|
|
489
|
+
value["method"] == "qualified_human" and provider is not None
|
|
490
|
+
) or (
|
|
491
|
+
value["method"] == "independent_model"
|
|
492
|
+
and (
|
|
493
|
+
provider is None
|
|
494
|
+
or provider["id"] == primary_provider["id"]
|
|
495
|
+
)
|
|
496
|
+
):
|
|
497
|
+
raise CommercialReviewBlocked("review.commercial.resolution_invalid")
|
|
498
|
+
return json.loads(_canonical_json({
|
|
499
|
+
**value,
|
|
500
|
+
"primary_provider": primary_provider,
|
|
501
|
+
"provider": provider,
|
|
502
|
+
}))
|
|
503
|
+
|
|
504
|
+
|
|
84
505
|
def public_profile(profile: str) -> dict[str, Any]:
|
|
85
506
|
"""Return the public, brand-neutral contract implemented by this module."""
|
|
86
507
|
body = {
|
|
87
508
|
"schema": PUBLIC_PROFILE_SCHEMA,
|
|
88
509
|
"profile": profile,
|
|
510
|
+
"review_evidence_schema": profile,
|
|
511
|
+
"review_evidence_contract": public_review_evidence_contract(profile),
|
|
89
512
|
"review_summary_schema": REVIEW_SUMMARY_SCHEMA,
|
|
90
513
|
"review_summary_contract": public_review_summary_contract(profile),
|
|
514
|
+
"review_routing_schema": REVIEW_ROUTING_SCHEMA,
|
|
515
|
+
"review_routing_contract": public_review_routing_contract(profile),
|
|
516
|
+
"review_resolution_schema": REVIEW_RESOLUTION_SCHEMA,
|
|
517
|
+
"review_resolution_contract": public_review_resolution_contract(
|
|
518
|
+
profile,
|
|
519
|
+
),
|
|
91
520
|
"applies_to": {
|
|
92
521
|
"content_type": "commercial",
|
|
93
522
|
"locales": "all-supported-target-locales",
|
|
@@ -124,11 +553,43 @@ def public_profile(profile: str) -> dict[str, Any]:
|
|
|
124
553
|
"method": "semantic-provider-evidence",
|
|
125
554
|
"deterministic_numeric_regex_is_sufficient": False,
|
|
126
555
|
"evidence_granularity": "every-proposition-per-offer",
|
|
556
|
+
"offer_registry": {
|
|
557
|
+
"identifiers": "unique",
|
|
558
|
+
"source_and_target_regions": "ordered-non-overlapping",
|
|
559
|
+
"discontiguous_regions_allowed": True,
|
|
560
|
+
"every_proposition_contained_in_declared_offer": True,
|
|
561
|
+
"every_offer_has_exactly_one_assignment_item": True,
|
|
562
|
+
"every_dimension_has_exactly_one_status_per_offer": True,
|
|
563
|
+
},
|
|
127
564
|
"directions": ["matched", "source_only", "target_only"],
|
|
128
565
|
"ambiguous_values": "unresolved",
|
|
129
566
|
"unresolved_route": "independent-model-or-qualified-native-domain-review",
|
|
130
567
|
"automatic_publication_when_unresolved": False,
|
|
131
568
|
},
|
|
569
|
+
"locale_quality_profile": {
|
|
570
|
+
"schema": COMMERCIAL_LOCALE_PROFILE_SCHEMA,
|
|
571
|
+
"required": True,
|
|
572
|
+
"binding_fields": [
|
|
573
|
+
"locale", "version", "commercial_profile",
|
|
574
|
+
"quality_profile_version", "quality_profile_sha256",
|
|
575
|
+
"rendering_reference", "sha256",
|
|
576
|
+
],
|
|
577
|
+
"rendering_reference": {
|
|
578
|
+
"schema": COMMERCIAL_RENDERING_REFERENCE_SCHEMA,
|
|
579
|
+
"authority": "Unicode CLDR",
|
|
580
|
+
"version": "48",
|
|
581
|
+
"purpose": "target-locale-rendering-guidance",
|
|
582
|
+
"semantic_proof": False,
|
|
583
|
+
"unresolved_route": (
|
|
584
|
+
"independent-model-or-qualified-native-domain-review"
|
|
585
|
+
),
|
|
586
|
+
},
|
|
587
|
+
"required_commercial_checks": list(DIMENSIONS),
|
|
588
|
+
"provider_phases": [
|
|
589
|
+
"transcreation", "target_native", "source_fidelity",
|
|
590
|
+
],
|
|
591
|
+
"tamper_policy": "block-before-provider",
|
|
592
|
+
},
|
|
132
593
|
"protected_terms": "project-configuration-only",
|
|
133
594
|
}
|
|
134
595
|
return {
|
|
@@ -153,8 +614,10 @@ all offers, headings, footnotes, links and conditions. Record every applicable p
|
|
|
153
614
|
offer label, semantic explanation and relation: 'matched', 'source_only' for an omission, or 'target_only' for an
|
|
154
615
|
addition. Give exact zero-based Python Unicode code-point spans with an exclusive end; the absent side of a one-sided
|
|
155
616
|
item MUST be null. Repeated amounts must stay attached to their own offer; number multisets do not prove fidelity.
|
|
617
|
+
'offer_statuses' MUST contain exactly one verdict for every registered offer, in registry order, for every dimension.
|
|
618
|
+
Derive the dimension status from those offer verdicts with precedence changed, uncertain, equivalent, not_present.
|
|
156
619
|
'not_present' is valid only if a dimension is absent from BOTH texts. 'equivalent' requires nonempty matched items
|
|
157
|
-
covering every applicable proposition. A
|
|
620
|
+
for that offer covering every applicable proposition. A per-offer 'changed' or 'uncertain' verdict requires at least one
|
|
158
621
|
specific item; use coverage='uncertain' for unresolved overall completeness without inventing a span.
|
|
159
622
|
Use 'changed' for a known defect and 'uncertain' for unresolved interpretation, coverage or insufficient language/domain
|
|
160
623
|
evidence. Use coverage='uncertain' unless every proposition and offer association was checked. Never resolve numeric
|
|
@@ -173,9 +636,18 @@ def review_contract(schema: str) -> dict[str, Any]:
|
|
|
173
636
|
return {
|
|
174
637
|
"schema": schema,
|
|
175
638
|
"coverage": "complete or uncertain",
|
|
639
|
+
"offers": [{
|
|
640
|
+
"id": "stable unique offer identifier",
|
|
641
|
+
"source_spans": [[0, 1]],
|
|
642
|
+
"target_spans": [[0, 1]],
|
|
643
|
+
}],
|
|
176
644
|
"checks": {
|
|
177
645
|
name: {
|
|
178
646
|
"status": "equivalent, not_present, changed or uncertain",
|
|
647
|
+
"offer_statuses": [{
|
|
648
|
+
"offer": "stable offer label",
|
|
649
|
+
"status": "equivalent, not_present, changed or uncertain",
|
|
650
|
+
}],
|
|
179
651
|
"items": [{
|
|
180
652
|
"offer": "stable offer label",
|
|
181
653
|
"relation": "matched, source_only, or target_only",
|
|
@@ -195,13 +667,16 @@ def validate_review(
|
|
|
195
667
|
target: str,
|
|
196
668
|
schema: str,
|
|
197
669
|
*,
|
|
670
|
+
target_locale: str,
|
|
671
|
+
commercial_quality_profile_version: str,
|
|
672
|
+
commercial_quality_profile_sha256: str,
|
|
198
673
|
allow_uncertain: bool = False,
|
|
199
674
|
) -> dict[str, Any]:
|
|
200
675
|
"""Validate evidence and return a content-free, hash-bound routing summary."""
|
|
201
676
|
def invalid() -> None:
|
|
202
677
|
raise CommercialReviewBlocked("review.commercial.invalid")
|
|
203
678
|
|
|
204
|
-
def span(value: Any, text: str) ->
|
|
679
|
+
def span(value: Any, text: str) -> tuple[int, int]:
|
|
205
680
|
if (
|
|
206
681
|
not isinstance(value, list) or len(value) != 2
|
|
207
682
|
or any(type(offset) is not int for offset in value)
|
|
@@ -209,55 +684,169 @@ def validate_review(
|
|
|
209
684
|
or not text[value[0]:value[1]].strip()
|
|
210
685
|
):
|
|
211
686
|
invalid()
|
|
687
|
+
return value[0], value[1]
|
|
688
|
+
|
|
689
|
+
def regions(value: Any, text: str) -> tuple[tuple[int, int], ...]:
|
|
690
|
+
if not isinstance(value, list) or len(value) > 1000:
|
|
691
|
+
invalid()
|
|
692
|
+
parsed = tuple(span(item, text) for item in value)
|
|
693
|
+
if list(parsed) != sorted(parsed) or any(
|
|
694
|
+
previous[1] > current[0]
|
|
695
|
+
for previous, current in zip(parsed, parsed[1:])
|
|
696
|
+
):
|
|
697
|
+
invalid()
|
|
698
|
+
return parsed
|
|
212
699
|
|
|
213
|
-
if
|
|
700
|
+
if (
|
|
701
|
+
not isinstance(target_locale, str)
|
|
702
|
+
or TARGET_LOCALE.fullmatch(target_locale) is None
|
|
703
|
+
or not isinstance(commercial_quality_profile_version, str)
|
|
704
|
+
or PROFILE_VERSION.fullmatch(commercial_quality_profile_version) is None
|
|
705
|
+
or not isinstance(commercial_quality_profile_sha256, str)
|
|
706
|
+
or len(commercial_quality_profile_sha256) != 64
|
|
707
|
+
or any(
|
|
708
|
+
character not in "0123456789abcdef"
|
|
709
|
+
for character in commercial_quality_profile_sha256
|
|
710
|
+
)
|
|
711
|
+
):
|
|
712
|
+
invalid()
|
|
713
|
+
if not isinstance(value, dict) or set(value) != {
|
|
714
|
+
"schema", "coverage", "offers", "checks",
|
|
715
|
+
}:
|
|
214
716
|
invalid()
|
|
215
717
|
if value["schema"] != schema or value["coverage"] not in ("complete", "uncertain"):
|
|
216
718
|
invalid()
|
|
719
|
+
offers = value["offers"]
|
|
720
|
+
if not isinstance(offers, list) or len(offers) > 1000:
|
|
721
|
+
invalid()
|
|
722
|
+
offer_regions: dict[str, dict[str, tuple[tuple[int, int], ...]]] = {}
|
|
723
|
+
occupied = {"source_spans": [], "target_spans": []}
|
|
724
|
+
for offer in offers:
|
|
725
|
+
if not isinstance(offer, dict) or set(offer) != {
|
|
726
|
+
"id", "source_spans", "target_spans",
|
|
727
|
+
}:
|
|
728
|
+
invalid()
|
|
729
|
+
offer_id = offer["id"]
|
|
730
|
+
if (
|
|
731
|
+
not isinstance(offer_id, str)
|
|
732
|
+
or PROFILE_VERSION.fullmatch(offer_id) is None
|
|
733
|
+
or offer_id in offer_regions
|
|
734
|
+
):
|
|
735
|
+
invalid()
|
|
736
|
+
parsed = {
|
|
737
|
+
"source_spans": regions(offer["source_spans"], source),
|
|
738
|
+
"target_spans": regions(offer["target_spans"], target),
|
|
739
|
+
}
|
|
740
|
+
if not parsed["source_spans"] and not parsed["target_spans"]:
|
|
741
|
+
invalid()
|
|
742
|
+
offer_regions[offer_id] = parsed
|
|
743
|
+
for side in occupied:
|
|
744
|
+
occupied[side].extend(
|
|
745
|
+
(start, end, offer_id) for start, end in parsed[side]
|
|
746
|
+
)
|
|
747
|
+
for side in occupied:
|
|
748
|
+
ordered = sorted(occupied[side])
|
|
749
|
+
if any(
|
|
750
|
+
previous[1] > current[0]
|
|
751
|
+
for previous, current in zip(ordered, ordered[1:])
|
|
752
|
+
):
|
|
753
|
+
invalid()
|
|
217
754
|
checks = value["checks"]
|
|
218
755
|
if not isinstance(checks, dict) or set(checks) != set(DIMENSIONS):
|
|
219
756
|
invalid()
|
|
220
757
|
uncertain_dimensions: set[str] = set()
|
|
758
|
+
uncertain_offers: dict[str, set[int]] = {
|
|
759
|
+
name: set() for name in DIMENSIONS
|
|
760
|
+
}
|
|
221
761
|
coverage_uncertain = value["coverage"] == "uncertain"
|
|
222
762
|
changed = False
|
|
223
763
|
evidenced = False
|
|
764
|
+
offer_ids = list(offer_regions)
|
|
765
|
+
status_priority = {
|
|
766
|
+
"not_present": 0,
|
|
767
|
+
"equivalent": 1,
|
|
768
|
+
"uncertain": 2,
|
|
769
|
+
"changed": 3,
|
|
770
|
+
}
|
|
224
771
|
for name, check in checks.items():
|
|
225
|
-
if not isinstance(check, dict) or set(check) != {
|
|
772
|
+
if not isinstance(check, dict) or set(check) != {
|
|
773
|
+
"status", "offer_statuses", "items",
|
|
774
|
+
}:
|
|
226
775
|
invalid()
|
|
227
|
-
status
|
|
776
|
+
status = check["status"]
|
|
777
|
+
offer_statuses = check["offer_statuses"]
|
|
778
|
+
items = check["items"]
|
|
228
779
|
if status not in ("equivalent", "not_present", "changed", "uncertain"):
|
|
229
780
|
invalid()
|
|
230
|
-
if not isinstance(items, list) or len(items) > 1000:
|
|
231
|
-
invalid()
|
|
232
781
|
if (
|
|
233
|
-
(
|
|
234
|
-
or (
|
|
782
|
+
not isinstance(offer_statuses, list)
|
|
783
|
+
or len(offer_statuses) != len(offer_ids)
|
|
235
784
|
):
|
|
236
785
|
invalid()
|
|
786
|
+
parsed_offer_statuses: dict[str, str] = {}
|
|
787
|
+
for index, offer_status in enumerate(offer_statuses):
|
|
788
|
+
if (
|
|
789
|
+
not isinstance(offer_status, dict)
|
|
790
|
+
or set(offer_status) != {"offer", "status"}
|
|
791
|
+
or offer_status.get("offer") != offer_ids[index]
|
|
792
|
+
or offer_status.get("status") not in status_priority
|
|
793
|
+
or offer_status["offer"] in parsed_offer_statuses
|
|
794
|
+
):
|
|
795
|
+
invalid()
|
|
796
|
+
parsed_offer_statuses[offer_status["offer"]] = (
|
|
797
|
+
offer_status["status"]
|
|
798
|
+
)
|
|
799
|
+
derived_status = (
|
|
800
|
+
max(parsed_offer_statuses.values(), key=status_priority.__getitem__)
|
|
801
|
+
if parsed_offer_statuses else "not_present"
|
|
802
|
+
)
|
|
803
|
+
if status != derived_status:
|
|
804
|
+
invalid()
|
|
805
|
+
if not isinstance(items, list) or len(items) > 1000:
|
|
806
|
+
invalid()
|
|
237
807
|
seen = set()
|
|
808
|
+
items_by_offer = {offer_id: [] for offer_id in offer_ids}
|
|
238
809
|
for item in items:
|
|
239
810
|
if not isinstance(item, dict) or set(item) != {
|
|
240
811
|
"offer", "relation", "source_span", "target_span", "explanation",
|
|
241
812
|
}:
|
|
242
813
|
invalid()
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
814
|
+
if (
|
|
815
|
+
not isinstance(item["offer"], str)
|
|
816
|
+
or PROFILE_VERSION.fullmatch(item["offer"]) is None
|
|
817
|
+
or item["offer"] not in offer_regions
|
|
818
|
+
or not isinstance(item["explanation"], str)
|
|
819
|
+
or not item["explanation"].strip()
|
|
820
|
+
or len(item["explanation"]) > 2000
|
|
821
|
+
):
|
|
822
|
+
invalid()
|
|
246
823
|
relation = item["relation"]
|
|
824
|
+
source_span = target_span = None
|
|
247
825
|
if relation == "matched":
|
|
248
|
-
span(item["source_span"], source)
|
|
249
|
-
span(item["target_span"], target)
|
|
826
|
+
source_span = span(item["source_span"], source)
|
|
827
|
+
target_span = span(item["target_span"], target)
|
|
250
828
|
elif relation == "source_only":
|
|
251
|
-
span(item["source_span"], source)
|
|
829
|
+
source_span = span(item["source_span"], source)
|
|
252
830
|
if item["target_span"] is not None:
|
|
253
831
|
invalid()
|
|
254
832
|
elif relation == "target_only":
|
|
255
833
|
if item["source_span"] is not None:
|
|
256
834
|
invalid()
|
|
257
|
-
span(item["target_span"], target)
|
|
835
|
+
target_span = span(item["target_span"], target)
|
|
258
836
|
else:
|
|
259
837
|
invalid()
|
|
260
|
-
|
|
838
|
+
declared = offer_regions[item["offer"]]
|
|
839
|
+
if source_span is not None and not any(
|
|
840
|
+
region[0] <= source_span[0]
|
|
841
|
+
and source_span[1] <= region[1]
|
|
842
|
+
for region in declared["source_spans"]
|
|
843
|
+
):
|
|
844
|
+
invalid()
|
|
845
|
+
if target_span is not None and not any(
|
|
846
|
+
region[0] <= target_span[0]
|
|
847
|
+
and target_span[1] <= region[1]
|
|
848
|
+
for region in declared["target_spans"]
|
|
849
|
+
):
|
|
261
850
|
invalid()
|
|
262
851
|
identity = (
|
|
263
852
|
item["offer"], relation,
|
|
@@ -267,10 +856,33 @@ def validate_review(
|
|
|
267
856
|
if identity in seen:
|
|
268
857
|
invalid()
|
|
269
858
|
seen.add(identity)
|
|
270
|
-
|
|
859
|
+
items_by_offer[item["offer"]].append(item)
|
|
860
|
+
for offer_id, offer_status in parsed_offer_statuses.items():
|
|
861
|
+
offer_items = items_by_offer[offer_id]
|
|
862
|
+
if (
|
|
863
|
+
(offer_status == "not_present" and offer_items)
|
|
864
|
+
or (
|
|
865
|
+
offer_status in ("equivalent", "changed", "uncertain")
|
|
866
|
+
and not offer_items
|
|
867
|
+
)
|
|
868
|
+
or (
|
|
869
|
+
offer_status == "equivalent"
|
|
870
|
+
and any(item["relation"] != "matched" for item in offer_items)
|
|
871
|
+
)
|
|
872
|
+
):
|
|
873
|
+
invalid()
|
|
874
|
+
if any(value == "uncertain" for value in parsed_offer_statuses.values()):
|
|
271
875
|
uncertain_dimensions.add(name)
|
|
272
|
-
|
|
273
|
-
|
|
876
|
+
uncertain_offers[name].update(
|
|
877
|
+
index for index, offer_id in enumerate(offer_ids)
|
|
878
|
+
if parsed_offer_statuses[offer_id] == "uncertain"
|
|
879
|
+
)
|
|
880
|
+
changed |= any(
|
|
881
|
+
value == "changed" for value in parsed_offer_statuses.values()
|
|
882
|
+
)
|
|
883
|
+
evidenced |= any(
|
|
884
|
+
value == "equivalent" for value in parsed_offer_statuses.values()
|
|
885
|
+
)
|
|
274
886
|
if changed:
|
|
275
887
|
raise CommercialReviewBlocked("review.commercial.changed")
|
|
276
888
|
# Every evidenced condition must resolve to an explicitly reviewed offer.
|
|
@@ -279,12 +891,22 @@ def validate_review(
|
|
|
279
891
|
check["status"] == "equivalent" for name, check in checks.items() if name != "offer_assignment"
|
|
280
892
|
):
|
|
281
893
|
uncertain_dimensions.add("offer_assignment")
|
|
894
|
+
if not uncertain_offers["offer_assignment"]:
|
|
895
|
+
uncertain_offers["offer_assignment"].update(
|
|
896
|
+
range(len(offer_ids))
|
|
897
|
+
)
|
|
282
898
|
else:
|
|
283
|
-
|
|
284
|
-
if
|
|
899
|
+
assigned = [item["offer"] for item in assignment["items"]]
|
|
900
|
+
if (
|
|
901
|
+
any(item["relation"] != "matched" for item in assignment["items"])
|
|
902
|
+
or len(assigned) != len(set(assigned))
|
|
903
|
+
or set(assigned) != set(offer_regions)
|
|
904
|
+
):
|
|
285
905
|
invalid()
|
|
286
906
|
if coverage_uncertain or not evidenced:
|
|
287
907
|
uncertain_dimensions.update(DIMENSIONS)
|
|
908
|
+
for name in DIMENSIONS:
|
|
909
|
+
uncertain_offers[name].update(range(len(offer_ids)))
|
|
288
910
|
summary = {
|
|
289
911
|
"schema": REVIEW_SUMMARY_SCHEMA,
|
|
290
912
|
"profile": schema,
|
|
@@ -292,7 +914,30 @@ def validate_review(
|
|
|
292
914
|
"review_required_dimensions": [
|
|
293
915
|
name for name in DIMENSIONS if name in uncertain_dimensions
|
|
294
916
|
],
|
|
295
|
-
"
|
|
917
|
+
"offer_count": len(offer_ids),
|
|
918
|
+
"review_required_offers": [
|
|
919
|
+
{
|
|
920
|
+
"dimension": name,
|
|
921
|
+
"offer_indexes": sorted(uncertain_offers[name]),
|
|
922
|
+
}
|
|
923
|
+
for name in DIMENSIONS if uncertain_offers[name]
|
|
924
|
+
],
|
|
925
|
+
"review_evidence_contract_sha256": (
|
|
926
|
+
public_review_evidence_contract(schema)["sha256"]
|
|
927
|
+
),
|
|
928
|
+
"evidence_sha256": evidence_sha256(
|
|
929
|
+
value,
|
|
930
|
+
source,
|
|
931
|
+
target,
|
|
932
|
+
schema,
|
|
933
|
+
target_locale=target_locale,
|
|
934
|
+
commercial_quality_profile_version=(
|
|
935
|
+
commercial_quality_profile_version
|
|
936
|
+
),
|
|
937
|
+
commercial_quality_profile_sha256=(
|
|
938
|
+
commercial_quality_profile_sha256
|
|
939
|
+
),
|
|
940
|
+
),
|
|
296
941
|
}
|
|
297
942
|
if uncertain_dimensions and not allow_uncertain:
|
|
298
943
|
raise CommercialReviewBlocked("review.commercial.independent_review_required")
|
|
@@ -310,24 +955,177 @@ def validate_summary(
|
|
|
310
955
|
not isinstance(value, dict)
|
|
311
956
|
or set(value) != {
|
|
312
957
|
"schema", "profile", "status", "review_required_dimensions",
|
|
313
|
-
"
|
|
958
|
+
"offer_count", "review_required_offers",
|
|
959
|
+
"review_evidence_contract_sha256", "evidence_sha256",
|
|
314
960
|
}
|
|
315
961
|
or value["schema"] != REVIEW_SUMMARY_SCHEMA
|
|
316
962
|
or value["profile"] != profile
|
|
963
|
+
or value["review_evidence_contract_sha256"]
|
|
964
|
+
!= public_review_evidence_contract(profile)["sha256"]
|
|
317
965
|
or value["status"] not in {"verified", "review_required"}
|
|
318
966
|
or not isinstance(value["evidence_sha256"], str)
|
|
319
967
|
or len(value["evidence_sha256"]) != 64
|
|
320
968
|
or any(character not in "0123456789abcdef" for character in value["evidence_sha256"])
|
|
321
969
|
or not isinstance(value["review_required_dimensions"], list)
|
|
970
|
+
or type(value["offer_count"]) is not int
|
|
971
|
+
or not 0 <= value["offer_count"] <= 1000
|
|
972
|
+
or not isinstance(value["review_required_offers"], list)
|
|
322
973
|
):
|
|
323
974
|
raise CommercialReviewBlocked("review.commercial.summary_invalid")
|
|
324
975
|
dimensions = value["review_required_dimensions"]
|
|
976
|
+
offer_scope = value["review_required_offers"]
|
|
325
977
|
if (
|
|
326
|
-
len(
|
|
978
|
+
len(offer_scope) > len(DIMENSIONS)
|
|
979
|
+
or len(dimensions) != len(set(dimensions))
|
|
327
980
|
or any(name not in DIMENSIONS for name in dimensions)
|
|
328
981
|
or dimensions != [name for name in DIMENSIONS if name in dimensions]
|
|
329
982
|
or (value["status"] == "verified") != (not dimensions)
|
|
983
|
+
or (value["status"] == "verified" and offer_scope)
|
|
330
984
|
or (value["status"] == "review_required" and not review_required)
|
|
331
985
|
):
|
|
332
986
|
raise CommercialReviewBlocked("review.commercial.summary_invalid")
|
|
987
|
+
previous_dimension_index = -1
|
|
988
|
+
seen_scope_dimensions: set[str] = set()
|
|
989
|
+
for item in offer_scope:
|
|
990
|
+
if (
|
|
991
|
+
not isinstance(item, dict)
|
|
992
|
+
or set(item) != {"dimension", "offer_indexes"}
|
|
993
|
+
or item.get("dimension") not in dimensions
|
|
994
|
+
or item["dimension"] in seen_scope_dimensions
|
|
995
|
+
or not isinstance(item.get("offer_indexes"), list)
|
|
996
|
+
or not item["offer_indexes"]
|
|
997
|
+
or any(type(index) is not int or not 0 <= index < value["offer_count"]
|
|
998
|
+
for index in item["offer_indexes"])
|
|
999
|
+
or item["offer_indexes"] != sorted(set(item["offer_indexes"]))
|
|
1000
|
+
):
|
|
1001
|
+
raise CommercialReviewBlocked("review.commercial.summary_invalid")
|
|
1002
|
+
dimension_index = list(DIMENSIONS).index(item["dimension"])
|
|
1003
|
+
if dimension_index <= previous_dimension_index:
|
|
1004
|
+
raise CommercialReviewBlocked("review.commercial.summary_invalid")
|
|
1005
|
+
previous_dimension_index = dimension_index
|
|
1006
|
+
seen_scope_dimensions.add(item["dimension"])
|
|
333
1007
|
return json.loads(_canonical_json(value))
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
def validate_review_routing_context(
|
|
1011
|
+
value: Any,
|
|
1012
|
+
source: str,
|
|
1013
|
+
target: str,
|
|
1014
|
+
summary: Any,
|
|
1015
|
+
profile: str,
|
|
1016
|
+
) -> dict[str, Any]:
|
|
1017
|
+
"""Validate private offer regions used only by an independent reviewer."""
|
|
1018
|
+
try:
|
|
1019
|
+
summary = validate_summary(summary, profile, review_required=True)
|
|
1020
|
+
except CommercialReviewBlocked:
|
|
1021
|
+
raise CommercialReviewBlocked("review.commercial.routing_invalid") from None
|
|
1022
|
+
if (
|
|
1023
|
+
summary["status"] != "review_required"
|
|
1024
|
+
or not isinstance(source, str)
|
|
1025
|
+
or not isinstance(target, str)
|
|
1026
|
+
or not isinstance(value, dict)
|
|
1027
|
+
or set(value) != {
|
|
1028
|
+
"schema", "profile", "contract_sha256", "offer_count",
|
|
1029
|
+
"source_length", "target_length", "offers",
|
|
1030
|
+
}
|
|
1031
|
+
or value.get("schema") != REVIEW_ROUTING_SCHEMA
|
|
1032
|
+
or value.get("profile") != profile
|
|
1033
|
+
or value.get("contract_sha256")
|
|
1034
|
+
!= public_review_routing_contract(profile)["sha256"]
|
|
1035
|
+
or value.get("offer_count") != summary["offer_count"]
|
|
1036
|
+
or type(value.get("source_length")) is not int
|
|
1037
|
+
or value["source_length"] != len(source)
|
|
1038
|
+
or type(value.get("target_length")) is not int
|
|
1039
|
+
or value["target_length"] != len(target)
|
|
1040
|
+
or not isinstance(value.get("offers"), list)
|
|
1041
|
+
or len(value["offers"]) != value["offer_count"]
|
|
1042
|
+
):
|
|
1043
|
+
raise CommercialReviewBlocked("review.commercial.routing_invalid")
|
|
1044
|
+
|
|
1045
|
+
occupied = {"source_spans": [], "target_spans": []}
|
|
1046
|
+
for expected_index, offer in enumerate(value["offers"]):
|
|
1047
|
+
if (
|
|
1048
|
+
not isinstance(offer, dict)
|
|
1049
|
+
or set(offer) != {
|
|
1050
|
+
"offer_index", "source_spans", "target_spans",
|
|
1051
|
+
}
|
|
1052
|
+
or offer.get("offer_index") != expected_index
|
|
1053
|
+
):
|
|
1054
|
+
raise CommercialReviewBlocked("review.commercial.routing_invalid")
|
|
1055
|
+
for field, text in (
|
|
1056
|
+
("source_spans", source), ("target_spans", target),
|
|
1057
|
+
):
|
|
1058
|
+
spans = offer.get(field)
|
|
1059
|
+
if not isinstance(spans, list) or len(spans) > 1000:
|
|
1060
|
+
raise CommercialReviewBlocked(
|
|
1061
|
+
"review.commercial.routing_invalid",
|
|
1062
|
+
)
|
|
1063
|
+
parsed = []
|
|
1064
|
+
for span in spans:
|
|
1065
|
+
if (
|
|
1066
|
+
not isinstance(span, list)
|
|
1067
|
+
or len(span) != 2
|
|
1068
|
+
or any(type(offset) is not int for offset in span)
|
|
1069
|
+
or not 0 <= span[0] < span[1] <= len(text)
|
|
1070
|
+
or not text[span[0]:span[1]].strip()
|
|
1071
|
+
):
|
|
1072
|
+
raise CommercialReviewBlocked(
|
|
1073
|
+
"review.commercial.routing_invalid",
|
|
1074
|
+
)
|
|
1075
|
+
parsed.append(tuple(span))
|
|
1076
|
+
if parsed != sorted(parsed) or any(
|
|
1077
|
+
previous[1] > current[0]
|
|
1078
|
+
for previous, current in zip(parsed, parsed[1:])
|
|
1079
|
+
):
|
|
1080
|
+
raise CommercialReviewBlocked(
|
|
1081
|
+
"review.commercial.routing_invalid",
|
|
1082
|
+
)
|
|
1083
|
+
occupied[field].extend(
|
|
1084
|
+
(start, end, expected_index) for start, end in parsed
|
|
1085
|
+
)
|
|
1086
|
+
if not offer["source_spans"] and not offer["target_spans"]:
|
|
1087
|
+
raise CommercialReviewBlocked("review.commercial.routing_invalid")
|
|
1088
|
+
for spans in occupied.values():
|
|
1089
|
+
ordered = sorted(spans)
|
|
1090
|
+
if any(
|
|
1091
|
+
previous[1] > current[0]
|
|
1092
|
+
for previous, current in zip(ordered, ordered[1:])
|
|
1093
|
+
):
|
|
1094
|
+
raise CommercialReviewBlocked("review.commercial.routing_invalid")
|
|
1095
|
+
return json.loads(_canonical_json(value))
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
def review_routing_context(
|
|
1099
|
+
evidence: Any,
|
|
1100
|
+
source: str,
|
|
1101
|
+
target: str,
|
|
1102
|
+
summary: Any,
|
|
1103
|
+
profile: str,
|
|
1104
|
+
) -> dict[str, Any]:
|
|
1105
|
+
"""Remove offer IDs and prose while retaining actionable private regions."""
|
|
1106
|
+
if (
|
|
1107
|
+
not isinstance(evidence, dict)
|
|
1108
|
+
or evidence.get("schema") != profile
|
|
1109
|
+
or not isinstance(evidence.get("offers"), list)
|
|
1110
|
+
):
|
|
1111
|
+
raise CommercialReviewBlocked("review.commercial.routing_invalid")
|
|
1112
|
+
context = {
|
|
1113
|
+
"schema": REVIEW_ROUTING_SCHEMA,
|
|
1114
|
+
"profile": profile,
|
|
1115
|
+
"contract_sha256": public_review_routing_contract(profile)["sha256"],
|
|
1116
|
+
"offer_count": len(evidence["offers"]),
|
|
1117
|
+
"source_length": len(source),
|
|
1118
|
+
"target_length": len(target),
|
|
1119
|
+
"offers": [
|
|
1120
|
+
{
|
|
1121
|
+
"offer_index": index,
|
|
1122
|
+
"source_spans": offer.get("source_spans"),
|
|
1123
|
+
"target_spans": offer.get("target_spans"),
|
|
1124
|
+
}
|
|
1125
|
+
if isinstance(offer, dict) else offer
|
|
1126
|
+
for index, offer in enumerate(evidence["offers"])
|
|
1127
|
+
],
|
|
1128
|
+
}
|
|
1129
|
+
return validate_review_routing_context(
|
|
1130
|
+
context, source, target, summary, profile,
|
|
1131
|
+
)
|