hermes: recover structured provider completion records

This commit is contained in:
jenkins 2026-09-13 18:09:47 -05:00
parent 9cc49dedeb
commit 3231e1af07
2 changed files with 38 additions and 6 deletions

View File

@ -22,6 +22,26 @@ PART = re.compile(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,127}\Z")
RESULT_FIELDS = frozenset({"status", "summary", "changed_files", "tests_run", "artifacts", "findings", "blockers"})
def _result_candidate(value: Any) -> dict[str, Any] | None:
"""Accept a direct result or the one canonical Claude session result field."""
if not isinstance(value, dict):
return None
candidate = value.get("structured_output") if "structured_output" in value else value
if not isinstance(candidate, dict) or set(candidate) != RESULT_FIELDS:
return None
if candidate.get("status") != "completed":
return None
if not isinstance(candidate.get("summary"), str) or not candidate["summary"].strip():
return None
if any(
not isinstance(candidate.get(name), list)
or any(not isinstance(item, str) for item in candidate[name])
for name in RESULT_FIELDS - {"status", "summary"}
):
return None
return candidate
def _completed_result(assignment: dict[str, Any]) -> dict[str, Any]:
"""Return exactly one completed result JSON object from an ordinal's safe log."""
parts = tuple(str(assignment[name]) for name in ("board", "task_id", "run_id"))
@ -54,13 +74,10 @@ def _completed_result(assignment: dict[str, Any]) -> dict[str, Any]:
value = json.loads(line)
except (UnicodeDecodeError, json.JSONDecodeError):
continue
if not isinstance(value, dict) or set(value) != RESULT_FIELDS or value.get("status") != "completed":
candidate = _result_candidate(value)
if candidate is None:
continue
if not isinstance(value.get("summary"), str) or not value["summary"].strip():
continue
if any(not isinstance(value.get(name), list) or any(not isinstance(item, str) for item in value[name]) for name in RESULT_FIELDS - {"status", "summary"}):
continue
candidates[canonical_json(value)] = value
candidates[canonical_json(candidate)] = candidate
if len(candidates) != 1:
raise ProtocolError("bootstrap result evidence is absent or ambiguous")
return next(iter(candidates.values()))

View File

@ -444,6 +444,21 @@ def test_mediator_bootstrap_recovers_one_unique_completed_log_result(tmp_path, m
assert seen["structured"] == completed and seen["request"]["title"] == completed["summary"]
def test_mediator_bootstrap_recovers_one_unique_nested_session_result(tmp_path, monkeypatch):
"""A Claude stream carries the completed result under structured_output."""
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 = dict(RESULT)
event = {"event": "result", "structured_output": completed}
log.write_bytes(protocol.canonical_json(event) + b"\n" + protocol.canonical_json(event) + b"\n")
monkeypatch.setattr(resume_bootstrap, "ROOT", tmp_path)
assert resume_bootstrap._completed_result(exact) == completed
def test_mediator_bootstrap_rejects_a_symlinked_log_ancestor(tmp_path, monkeypatch):
exact = protocol.sign_envelope(KEY, "assignment", binding(), payload())
outside = tmp_path / "outside"