blun-king-cli 9.1.597 → 9.1.600

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +17 -1
  3. package/agent-spine-plugin/CHANGELOG.md +1 -1
  4. package/agent-spine-plugin/docs/host-integration.md +1 -15
  5. package/agent-spine-plugin/docs/preflight-recall.md +1 -1
  6. package/agent-spine-plugin/scripts/check-install.js +1 -6
  7. package/agent-spine-plugin/scripts/hermetic-process.js +8 -0
  8. package/agent-spine-plugin/scripts/release-check.js +2 -3
  9. package/agent-spine-plugin/scripts/run-tests-hermetic.js +8 -11
  10. package/agent-spine-plugin/src/hook.js +40 -40
  11. package/agent-spine-plugin/src/lib/briefing.js +6 -3
  12. package/agent-spine-plugin/src/lib/hook-context.js +63 -64
  13. package/agent-spine-plugin/src/lib/hook-output.js +115 -94
  14. package/agent-spine-plugin/src/lib/hook-timeline.js +20 -11
  15. package/agent-spine-plugin/src/lib/host-instruction-budget.js +8 -14
  16. package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +0 -7
  17. package/agent-spine-plugin/src/lib/pre-answer-timeline-recall.js +104 -0
  18. package/agent-spine-plugin/src/lib/session-timeline-codex.js +0 -4
  19. package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +0 -3
  20. package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +0 -4
  21. package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +0 -2
  22. package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +0 -22
  23. package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +0 -4
  24. package/agent-spine-plugin/src/lib/session-timeline-prior.js +42 -50
  25. package/agent-spine-plugin/src/lib/session-timeline-provider.js +0 -3
  26. package/agent-spine-plugin/src/lib/session-timeline-query.js +0 -1
  27. package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +0 -4
  28. package/agent-spine-plugin/src/lib/session-timeline-source.js +0 -3
  29. package/agent-spine-plugin/src/lib/session-timeline-transport.js +0 -8
  30. package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +0 -3
  31. package/agent-spine-plugin/src/lib/session-timeline.js +370 -408
  32. package/agent-spine-plugin/src/lib/source-roots.js +26 -16
  33. package/agent-spine-plugin/src/lib/timeline-user-feedback.js +0 -1
  34. package/bin/core-bootstrap.js +18 -10
  35. package/bin/launcher-mode.js +5 -0
  36. package/bin/launcher-runtime.js +27 -0
  37. package/bin/verify-bundled-agent-sources.cjs +28 -2
  38. package/blun.mjs +798 -143
  39. package/bundled-agent-sources.json +192 -155
  40. package/package.json +1 -1
  41. package/standard-skills/translate-native/README.md +1334 -1
  42. package/standard-skills/translate-native/SKILL.md +1 -1
  43. package/standard-skills/translate-native/VERSION +1 -1
  44. package/standard-skills/translate-native/docs/PREMORTEM.md +901 -0
  45. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +208 -41
  46. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1319 -77
  47. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +66 -11
  48. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +19 -1
  49. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +24 -6
  50. package/standard-skills/translate-native/integrations/commercial_localization_profile.py +23 -0
  51. package/standard-skills/translate-native/integrations/website_localization.py +234 -10
  52. package/standard-skills/translate-native/integrations/website_localization_benchmark.py +39 -3
  53. package/standard-skills/translate-native/integrations/website_localization_cms.py +512 -10
  54. package/standard-skills/translate-native/integrations/website_localization_cms_client.py +116 -0
  55. package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +101 -11
  56. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +12 -1
  57. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +186 -24
  58. package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +64 -1
  59. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +528 -5
  60. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth.py +918 -0
  61. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth_runtime.py +609 -0
  62. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_client.py +885 -0
  63. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_http.py +1244 -0
  64. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +220 -0
  65. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_sidecar_adapter.py +331 -0
  66. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_capabilities_http.py +444 -0
  67. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_client.py +673 -0
  68. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch.py +1317 -0
  69. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_client.py +826 -0
  70. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_http.py +1152 -0
  71. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_openapi.py +896 -0
  72. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_runtime.py +621 -0
  73. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_http.py +1180 -0
  74. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_runtime.py +1479 -0
  75. package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +133 -17
  76. package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +319 -4
  77. package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +72 -2
  78. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +13 -0
  79. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +56 -13
  80. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_openapi.py +335 -0
  81. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +66 -1
  82. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +73 -7
  83. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +93 -9
  84. package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +221 -11
  85. package/standard-skills/translate-native/integrations/website_localization_health.py +6 -0
  86. package/standard-skills/translate-native/integrations/website_localization_http_provider.py +1 -1
  87. package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +350 -0
  88. package/standard-skills/translate-native/integrations/website_localization_queue.py +126 -56
  89. package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +166 -13
  90. package/standard-skills/translate-native/integrations/website_localization_release.py +423 -17
  91. package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +168 -13
  92. package/standard-skills/translate-native/integrations/website_localization_runner.py +10 -0
  93. package/standard-skills/translate-native/integrations/website_localization_worker.py +213 -9
  94. package/standard-skills/translate-native/provenance.json +2 -2
  95. package/standard-skills/translate-native/references/commercial-localization.md +96 -17
  96. package/standard-skills/translate-native/scripts/blun_language_guard.py +3 -1
  97. package/standard-skills/translate-native/scripts/check_commercial_review.py +69 -9
  98. package/standard-skills/translate-native/scripts/commercial_localization_profile.py +829 -31
  99. package/standard-tools/language-guard/VERSION +1 -1
  100. package/standard-tools/language-guard/blun_language_guard.py +3 -1
  101. package/standard-tools/language-guard/check_commercial_review.py +69 -9
  102. package/standard-tools/language-guard/commercial_localization_profile.py +829 -31
  103. package/standard-tools/language-guard/provenance.json +2 -2
  104. package/standard-tools/manifest.json +1 -1
  105. package/worker-host.mjs +215 -82
  106. package/agent-spine-plugin/scripts/check-install-king.js +0 -37
@@ -4,20 +4,23 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import hashlib
7
+ import importlib.util
7
8
  import json
8
9
  import re
9
10
  import socket
11
+ import sys
10
12
  import unicodedata
11
13
  import urllib.error
12
14
  import urllib.parse
13
15
  import urllib.request
14
16
  from dataclasses import dataclass
17
+ from pathlib import Path
15
18
  from typing import Any, Callable, Mapping, Protocol
16
19
 
17
20
 
18
21
  REQUEST_SCHEMA = "blun.localization-quality-evidence-http-request.v1"
19
22
  RESPONSE_SCHEMA = "blun.localization-quality-evidence-http-response.v1"
20
- EVIDENCE_REQUEST_SCHEMA = "blun.localization-quality-evidence-request.v5"
23
+ EVIDENCE_REQUEST_SCHEMA = "blun.localization-quality-evidence-request.v14"
21
24
  EVIDENCE_RESPONSE_SCHEMA = "blun.localization-quality-evidence-response.v2"
22
25
  MAX_ENDPOINT_LENGTH = 2048
23
26
  MAX_HEADER_VALUE_LENGTH = 4096
@@ -29,7 +32,7 @@ REQUEST_ID = re.compile(r"^blun-l10n-evidence-[0-9a-f]{64}$")
29
32
  SHA256 = re.compile(r"^[0-9a-f]{64}$")
30
33
  TOKEN = re.compile(r"^[A-Za-z0-9_.:-]{1,256}$")
31
34
  ERROR_CODE = re.compile(r"^[a-z][a-z0-9_.-]{0,127}$")
32
- COMMERCIAL_REVIEW_SUMMARY_SCHEMA = "translate-native.commercial-review-summary.v1"
35
+ COMMERCIAL_REVIEW_SUMMARY_SCHEMA = "translate-native.commercial-review-summary.v6"
33
36
  COMMERCIAL_DIMENSIONS = (
34
37
  "amount_currency", "discount_basis", "qualifiers", "tax_status",
35
38
  "billing_interval", "commitment", "renewal", "cancellation",
@@ -41,9 +44,26 @@ REQUEST_FIELDS = {
41
44
  "source_locale", "target_locale", "content_type", "glossary_version",
42
45
  "policy_version", "provider", "software_version", "source_text",
43
46
  "target_text", "review_confidence", "quality_profile",
44
- "commercial_profile", "commercial_review", "human_review_required",
47
+ "commercial_profile", "commercial_review", "commercial_review_routing",
48
+ "commercial_review_routing_contract_sha256",
49
+ "commercial_review_routing_contract",
50
+ "human_review_required",
51
+ "commercial_review_resolution_contract_sha256",
52
+ "commercial_review_resolution_contract",
45
53
  "independent_review_required",
46
54
  }
55
+ EVIDENCE_REQUEST_IDENTITY_FIELDS = (
56
+ "schema", "evidence_revision", "event_id", "plan_id", "job_id",
57
+ "result_sha256", "source_sha256", "target_sha256", "source_locale",
58
+ "target_locale", "content_type", "glossary_version", "policy_version",
59
+ "provider", "software_version", "review_confidence", "quality_profile",
60
+ "commercial_profile", "commercial_review", "commercial_review_routing",
61
+ "commercial_review_routing_contract_sha256",
62
+ "commercial_review_routing_contract",
63
+ "commercial_review_resolution_contract_sha256",
64
+ "commercial_review_resolution_contract", "human_review_required",
65
+ "independent_review_required",
66
+ )
47
67
  EVIDENCE_FIELDS = {
48
68
  "schema", "request_id", "result_sha256", "quality_receipt",
49
69
  "human_review_receipt", "independent_model_review",
@@ -56,6 +76,40 @@ RESERVED_HEADERS = {
56
76
  }
57
77
 
58
78
 
79
+ def _commercial_offer_scope(
80
+ value: Any,
81
+ dimensions: list[str],
82
+ offer_count: Any,
83
+ ) -> bool:
84
+ if type(offer_count) is not int or not 0 <= offer_count <= 1000:
85
+ return False
86
+ if not isinstance(value, list) or len(value) > len(COMMERCIAL_DIMENSIONS):
87
+ return False
88
+ previous = -1
89
+ seen: set[str] = set()
90
+ for item in value:
91
+ if (
92
+ not isinstance(item, dict)
93
+ or set(item) != {"dimension", "offer_indexes"}
94
+ or item.get("dimension") not in dimensions
95
+ or item["dimension"] in seen
96
+ or not isinstance(item.get("offer_indexes"), list)
97
+ or not item["offer_indexes"]
98
+ or any(
99
+ type(index) is not int or not 0 <= index < offer_count
100
+ for index in item["offer_indexes"]
101
+ )
102
+ or item["offer_indexes"] != sorted(set(item["offer_indexes"]))
103
+ ):
104
+ return False
105
+ position = COMMERCIAL_DIMENSIONS.index(item["dimension"])
106
+ if position <= previous:
107
+ return False
108
+ previous = position
109
+ seen.add(item["dimension"])
110
+ return True
111
+
112
+
59
113
  class HTTPEvidenceProviderFailed(RuntimeError):
60
114
  """Content-free adapter failure understood by release coordination."""
61
115
 
@@ -71,6 +125,23 @@ class HTTPEvidenceProviderFailed(RuntimeError):
71
125
  self.retryable = retryable
72
126
 
73
127
 
128
+ def _load_module(name: str, path: Path):
129
+ spec = importlib.util.spec_from_file_location(name, path)
130
+ if spec is None or spec.loader is None:
131
+ raise RuntimeError(f"cannot load evidence dependency: {path.name}")
132
+ module = importlib.util.module_from_spec(spec)
133
+ sys.modules[spec.name] = module
134
+ spec.loader.exec_module(module)
135
+ return module
136
+
137
+
138
+ _ROOT = Path(__file__).resolve().parents[1]
139
+ _COMMERCIAL = _load_module(
140
+ "blun_website_localization_evidence_http_commercial",
141
+ _ROOT / "integrations" / "commercial_localization_profile.py",
142
+ )
143
+
144
+
74
145
  @dataclass(frozen=True)
75
146
  class HTTPResult:
76
147
  status: int
@@ -145,6 +216,19 @@ def _canonical_json(value: Any, *, code: str, maximum: int) -> bytes:
145
216
  return encoded
146
217
 
147
218
 
219
+ def _request_id_for_payload(payload: Mapping[str, Any]) -> str:
220
+ identity = {
221
+ field: payload[field]
222
+ for field in EVIDENCE_REQUEST_IDENTITY_FIELDS
223
+ }
224
+ digest = hashlib.sha256(_canonical_json(
225
+ identity,
226
+ code="request_invalid",
227
+ maximum=MAX_REQUEST_BYTES,
228
+ )).hexdigest()
229
+ return "blun-l10n-evidence-" + digest
230
+
231
+
148
232
  def _pairs(items):
149
233
  result = {}
150
234
  for key, value in items:
@@ -265,6 +349,40 @@ def _safe_text(value: Any) -> bool:
265
349
  )
266
350
 
267
351
 
352
+ def _quality_profile(
353
+ value: Any,
354
+ *,
355
+ target_locale: Any,
356
+ content_type: Any,
357
+ commercial_profile: Any,
358
+ ) -> bool:
359
+ commercial = commercial_profile is not None
360
+ expected_fields = {"locale", "version", "sha256"}
361
+ if commercial:
362
+ expected_fields.add("commercial")
363
+ if (
364
+ not isinstance(value, dict)
365
+ or set(value) != expected_fields
366
+ or value.get("locale") != target_locale
367
+ or not _token(value.get("version"))
368
+ or not isinstance(value.get("sha256"), str)
369
+ or SHA256.fullmatch(value["sha256"]) is None
370
+ or (content_type == "commercial") != commercial
371
+ ):
372
+ return False
373
+ if not commercial:
374
+ return True
375
+ nested = value.get("commercial")
376
+ return (
377
+ isinstance(nested, dict)
378
+ and set(nested) == {"profile", "version", "sha256"}
379
+ and nested.get("profile") == commercial_profile
380
+ and _token(nested.get("version"))
381
+ and isinstance(nested.get("sha256"), str)
382
+ and SHA256.fullmatch(nested["sha256"]) is not None
383
+ )
384
+
385
+
268
386
  def _request_payload(request: Any) -> tuple[dict[str, Any], bytes]:
269
387
  try:
270
388
  payload = request.as_payload()
@@ -303,6 +421,13 @@ def _request_payload(request: Any) -> tuple[dict[str, Any], bytes]:
303
421
  confidence = payload["review_confidence"]
304
422
  profile = payload["quality_profile"]
305
423
  commercial_review = payload["commercial_review"]
424
+ commercial_review_routing = payload["commercial_review_routing"]
425
+ commercial_review_routing_contract_sha256 = payload[
426
+ "commercial_review_routing_contract_sha256"
427
+ ]
428
+ commercial_review_routing_contract = payload[
429
+ "commercial_review_routing_contract"
430
+ ]
306
431
  if (
307
432
  not isinstance(provider, dict)
308
433
  or set(provider) != {"id", "model_id", "model_version"}
@@ -310,12 +435,12 @@ def _request_payload(request: Any) -> tuple[dict[str, Any], bytes]:
310
435
  or not isinstance(confidence, dict)
311
436
  or set(confidence) != {"target_native", "source_fidelity"}
312
437
  or any(value not in {"high", "low"} for value in confidence.values())
313
- or not isinstance(profile, dict)
314
- or set(profile) != {"locale", "version", "sha256"}
315
- or profile["locale"] != payload["target_locale"]
316
- or not _token(profile["version"])
317
- or not isinstance(profile["sha256"], str)
318
- or SHA256.fullmatch(profile["sha256"]) is None
438
+ or not _quality_profile(
439
+ profile,
440
+ target_locale=payload["target_locale"],
441
+ content_type=payload["content_type"],
442
+ commercial_profile=payload["commercial_profile"],
443
+ )
319
444
  or type(payload["human_review_required"]) is not bool
320
445
  or type(payload["independent_review_required"]) is not bool
321
446
  or (
@@ -329,10 +454,16 @@ def _request_payload(request: Any) -> tuple[dict[str, Any], bytes]:
329
454
  not isinstance(commercial_review, dict)
330
455
  or set(commercial_review) != {
331
456
  "schema", "profile", "status",
332
- "review_required_dimensions", "evidence_sha256",
457
+ "review_required_dimensions",
458
+ "offer_count", "review_required_offers",
459
+ "review_evidence_contract_sha256", "evidence_sha256",
333
460
  }
334
461
  or commercial_review["schema"] != COMMERCIAL_REVIEW_SUMMARY_SCHEMA
335
462
  or commercial_review["profile"] != payload["commercial_profile"]
463
+ or commercial_review["review_evidence_contract_sha256"]
464
+ != _COMMERCIAL.public_review_evidence_contract(
465
+ payload["commercial_profile"],
466
+ )["sha256"]
336
467
  or commercial_review["status"] not in {
337
468
  "verified", "review_required",
338
469
  }
@@ -345,9 +476,17 @@ def _request_payload(request: Any) -> tuple[dict[str, Any], bytes]:
345
476
  ]
346
477
  or len(commercial_review["review_required_dimensions"])
347
478
  != len(set(commercial_review["review_required_dimensions"]))
479
+ or not _commercial_offer_scope(
480
+ commercial_review["review_required_offers"],
481
+ commercial_review["review_required_dimensions"],
482
+ commercial_review["offer_count"],
483
+ )
348
484
  or (
349
485
  commercial_review["status"] == "verified"
350
- and commercial_review["review_required_dimensions"]
486
+ and (
487
+ commercial_review["review_required_dimensions"]
488
+ or commercial_review["review_required_offers"]
489
+ )
351
490
  )
352
491
  or (
353
492
  commercial_review["status"] == "review_required"
@@ -362,6 +501,77 @@ def _request_payload(request: Any) -> tuple[dict[str, Any], bytes]:
362
501
  )
363
502
  ):
364
503
  raise HTTPEvidenceProviderFailed("request_invalid", retryable=False)
504
+ try:
505
+ expected_routing_contract_sha256 = (
506
+ _COMMERCIAL.public_review_routing_contract(
507
+ payload["commercial_profile"],
508
+ )["sha256"]
509
+ if commercial_review is not None
510
+ else None
511
+ )
512
+ if (
513
+ commercial_review_routing_contract_sha256
514
+ != expected_routing_contract_sha256
515
+ ):
516
+ raise _COMMERCIAL.CommercialReviewBlocked(
517
+ "review.commercial.routing_invalid",
518
+ )
519
+ if (
520
+ commercial_review is not None
521
+ and commercial_review["status"] == "review_required"
522
+ ):
523
+ if commercial_review_routing_contract != (
524
+ _COMMERCIAL.public_review_routing_contract(
525
+ payload["commercial_profile"],
526
+ )
527
+ ):
528
+ raise _COMMERCIAL.CommercialReviewBlocked(
529
+ "review.commercial.routing_invalid",
530
+ )
531
+ _COMMERCIAL.validate_review_routing_context(
532
+ commercial_review_routing,
533
+ source_text,
534
+ target_text,
535
+ commercial_review,
536
+ payload["commercial_profile"],
537
+ )
538
+ elif (
539
+ commercial_review_routing is not None
540
+ or commercial_review_routing_contract is not None
541
+ ):
542
+ raise _COMMERCIAL.CommercialReviewBlocked(
543
+ "review.commercial.routing_invalid",
544
+ )
545
+ except (
546
+ _COMMERCIAL.CommercialReviewBlocked,
547
+ KeyError,
548
+ TypeError,
549
+ ValueError,
550
+ ):
551
+ raise HTTPEvidenceProviderFailed(
552
+ "request_invalid", retryable=False,
553
+ ) from None
554
+ expected_resolution_contract = (
555
+ _COMMERCIAL.public_review_resolution_contract(
556
+ payload["commercial_profile"],
557
+ )
558
+ if commercial_review is not None
559
+ and commercial_review["status"] == "review_required"
560
+ else None
561
+ )
562
+ if (
563
+ payload["commercial_review_resolution_contract_sha256"]
564
+ != (
565
+ expected_resolution_contract["sha256"]
566
+ if expected_resolution_contract is not None
567
+ else None
568
+ )
569
+ or payload["commercial_review_resolution_contract"]
570
+ != expected_resolution_contract
571
+ ):
572
+ raise HTTPEvidenceProviderFailed("request_invalid", retryable=False)
573
+ if request_id != _request_id_for_payload(payload):
574
+ raise HTTPEvidenceProviderFailed("request_invalid", retryable=False)
365
575
  return payload, _canonical_json(
366
576
  payload, code="request_invalid", maximum=MAX_REQUEST_BYTES,
367
577
  )
@@ -399,6 +399,11 @@ class LocalizationHealthMonitor:
399
399
  raise ValueError
400
400
  if payload.get("target", {}).get("locale") != row["target_locale"]:
401
401
  raise ValueError
402
+ try:
403
+ _RELEASE._validated_job_payload(payload)
404
+ except _RELEASE.LocalizationReleaseBlocked:
405
+ reasons.add("queue.job_binding_invalid")
406
+ continue
402
407
  if row["status"] == "succeeded":
403
408
  self.queue.result(row["job_id"])
404
409
  if row["status"] == "leased" and float(row["lease_expires_at"]) <= now:
@@ -1432,6 +1437,7 @@ class LocalizationHealthMonitor:
1432
1437
  benchmark_references = self._check_native_reference_queue(now)
1433
1438
  blocking_workflow = {
1434
1439
  "queue.state_invalid",
1440
+ "queue.job_binding_invalid",
1435
1441
  "evidence.state_invalid",
1436
1442
  "release.approval_invalid",
1437
1443
  "cms.delivery.invalid",
@@ -22,7 +22,7 @@ MAX_HEADER_VALUE_LENGTH = 4096
22
22
  HEADER_NAME = re.compile(r"^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$")
23
23
  ERROR_CODE = re.compile(r"^[a-z][a-z0-9_.-]{0,127}$")
24
24
  REQUEST_ID = re.compile(r"^blun-l10n-call-[a-f0-9]{64}$")
25
- WORKER_REQUEST_SCHEMA = "blun.website-localization-worker.v4"
25
+ WORKER_REQUEST_SCHEMA = "blun.website-localization-worker.v9"
26
26
  WORKER_REQUEST_FIELDS = {
27
27
  "schema", "request_id", "phase", "provider_id", "model_id",
28
28
  "model_version", "system_instruction", "input",