85 lines
4.2 KiB
Python
85 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Fail-closed one-time normalization of a mediator publication receipt."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from typing import Any
|
|
|
|
from execution_pool_protocol import truncate_utf8
|
|
from publication_retry import receipt_digest
|
|
import supervisor_state
|
|
|
|
|
|
def canonical_title(summary: Any) -> str:
|
|
"""Apply the broker's character and UTF-8-byte title limits."""
|
|
if not isinstance(summary, str) or not (text := summary.strip()):
|
|
raise ValueError("publication retry summary is invalid")
|
|
return truncate_utf8(text[:240], 507)
|
|
|
|
|
|
def normalize(
|
|
board: str, child_task_id: str, run_id: str, raw_result_sha256: str, receipt: Any,
|
|
) -> str:
|
|
"""Replace only a rejected title on the exact pending mediator receipt."""
|
|
if not isinstance(receipt, dict) or not isinstance(raw_result_sha256, str) or len(raw_result_sha256) != 64:
|
|
raise ValueError("publication retry normalization input is invalid")
|
|
with supervisor_state._connect(board) as connection:
|
|
row = connection.execute(
|
|
"SELECT receipt_json,issued_run_id,resolved_run_id,reissue_count,last_reissued_run_id FROM publication_retries "
|
|
"WHERE board=? AND child_task_id=?", (board, child_task_id)
|
|
).fetchone()
|
|
provenance = connection.execute(
|
|
"SELECT raw_result_sha256,reconstruction FROM publication_retry_provenance "
|
|
"WHERE board=? AND child_task_id=?", (board, child_task_id)
|
|
).fetchone()
|
|
if row is None or provenance is None or provenance[0] != raw_result_sha256:
|
|
raise ValueError("publication retry provenance is unavailable")
|
|
pending = (run_id, "", 0, "")
|
|
released = ("", "", 1, run_id)
|
|
if row[1:] not in {pending, released}:
|
|
raise ValueError("publication retry is not the exact pending run")
|
|
try:
|
|
old = json.loads(row[0])
|
|
except (TypeError, json.JSONDecodeError) as error:
|
|
raise ValueError("sealed publication receipt is malformed") from error
|
|
binding = old.get("source") if isinstance(old, dict) else None
|
|
if not isinstance(binding, dict):
|
|
raise ValueError("sealed publication receipt is malformed")
|
|
old, _ordinal, _source_run = supervisor_state._retry_receipt(
|
|
board, child_task_id, binding, old, path=None
|
|
)
|
|
new, _ordinal, _source_run = supervisor_state._retry_receipt(
|
|
board, child_task_id, binding, receipt, path=None
|
|
)
|
|
unchanged = ("source", "baseline_sha", "head", "body", "structured")
|
|
if any(old[name] != new[name] for name in unchanged):
|
|
raise ValueError("publication retry evidence changed during normalization")
|
|
expected = canonical_title(old["structured"].get("summary"))
|
|
if new["title"] != expected or new["result_digest"] != receipt_digest(
|
|
new["structured"], new["title"], new["body"]
|
|
):
|
|
raise ValueError("publication retry title normalization is invalid")
|
|
encoded = json.dumps(new, separators=(",", ":"), sort_keys=True)
|
|
prefix = "normalized-title-from-sealed-receipt-sha256:"
|
|
if row[0] == encoded:
|
|
sealed_sha = provenance[1][len(prefix):] if isinstance(provenance[1], str) else ""
|
|
if not isinstance(provenance[1], str) or not provenance[1].startswith(prefix) or len(sealed_sha) != 64:
|
|
raise ValueError("publication retry normalization provenance conflicts")
|
|
return sealed_sha
|
|
sealed_sha = hashlib.sha256(row[0].encode()).hexdigest()
|
|
marker = prefix + sealed_sha
|
|
changed = connection.execute(
|
|
"UPDATE publication_retries SET receipt_json=? WHERE board=? AND child_task_id=? "
|
|
"AND receipt_json=? AND issued_run_id=? AND resolved_run_id='' AND reissue_count=0",
|
|
(encoded, board, child_task_id, row[0], run_id),
|
|
).rowcount
|
|
if changed != 1:
|
|
raise ValueError("publication retry changed during normalization")
|
|
connection.execute(
|
|
"UPDATE publication_retry_provenance SET reconstruction=? WHERE board=? AND child_task_id=?",
|
|
(marker, board, child_task_id),
|
|
)
|
|
return sealed_sha
|