hermes: bound publication titles by UTF-8 bytes

This commit is contained in:
jenkins 2026-09-13 18:17:39 -05:00
parent 3231e1af07
commit cac4c206cd
4 changed files with 35 additions and 3 deletions

View File

@ -93,6 +93,13 @@ def payload_digest(payload: Any) -> str:
return hashlib.sha256(canonical_json(payload)).hexdigest()
def truncate_utf8(value: str, maximum: int) -> str:
"""Bound display text by UTF-8 bytes without splitting a character."""
if maximum < 0:
raise ProtocolError("text byte limit is invalid")
return value.encode("utf-8", "replace")[:maximum].decode("utf-8", "ignore")
def derive_ordinal_key(master: bytes, ordinal: int) -> bytes:
"""Derive one cryptographically isolated worker authority from the pool root."""
if ordinal not in range(3) or not 32 <= len(master) <= 4096:

View File

@ -19,6 +19,7 @@ from execution_pool_protocol import (
ProtocolError,
atomic_json,
canonical_json,
truncate_utf8,
)
ROOT = Path(os.environ.get("HERMES_WORKER_ROOT", "/workspace"))
ORDINAL = int(os.environ.get("HERMES_WORKER_ORDINAL", "-1"))
@ -380,7 +381,7 @@ def execute(assignment: dict[str, Any]) -> None:
"finish",
binding=binding,
payload=result_payload,
title=str(structured.get("summary") or f"Hermes task {binding['task_id']}")[:240],
title=truncate_utf8(str(structured.get("summary") or f"Hermes task {binding['task_id']}"), 512),
body=json.dumps(structured, indent=2, sort_keys=True)[:12000],
)
if not response.get("ack", {}).get("accepted"):

View File

@ -12,7 +12,7 @@ import sys
from pathlib import Path
from typing import Any
from execution_pool_protocol import ProtocolError, canonical_json, read_key
from execution_pool_protocol import ProtocolError, canonical_json, read_key, truncate_utf8
from execution_pool_scm import Boundary
ROOT = Path(os.environ.get("HERMES_WORKER_ROOT", "/workspace"))
@ -88,7 +88,7 @@ def bootstrap(key: bytes, raw_assignment: Any) -> dict[str, Any]:
boundary = Boundary(key)
assignment = boundary.verify(raw_assignment)
structured = _completed_result(assignment)
title = structured["summary"].strip()[:512]
title = truncate_utf8(structured["summary"].strip(), 512)
body = json.dumps(structured, indent=2, sort_keys=True)
return boundary.resume_artifact(assignment, {"title": title, "body": body}, structured)

View File

@ -459,6 +459,30 @@ def test_mediator_bootstrap_recovers_one_unique_nested_session_result(tmp_path,
assert resume_bootstrap._completed_result(exact) == completed
def test_mediator_bootstrap_truncates_multibyte_title_at_the_byte_limit(tmp_path, monkeypatch):
"""Receipt title limits count UTF-8 bytes while preserving full evidence."""
exact = protocol.sign_envelope(
KEY, "assignment", binding(), payload(root_task_id="t_deadbeef", continuation_kind="repair")
)
log = tmp_path / "session-state" / "metis" / "t_deadbeef" / "42.log"
log.parent.mkdir(parents=True)
completed = {**RESULT, "summary": "" * 200}
log.write_bytes(protocol.canonical_json({"structured_output": completed}) + b"\n")
monkeypatch.setattr(resume_bootstrap, "ROOT", tmp_path)
seen = {}
monkeypatch.setattr(
scm.Boundary, "resume_artifact",
lambda _self, _assignment, request, structured: seen.update(
request=request, structured=structured
) or {},
)
resume_bootstrap.bootstrap(KEY, exact)
assert len(seen["request"]["title"].encode()) <= 512
assert seen["structured"]["summary"] == completed["summary"]
def test_mediator_bootstrap_rejects_a_symlinked_log_ancestor(tmp_path, monkeypatch):
exact = protocol.sign_envelope(KEY, "assignment", binding(), payload())
outside = tmp_path / "outside"