fix: inspect failed runs without checkpoints

This commit is contained in:
lda
2026-09-09 23:55:19 +07:00 Verified
parent 939eae85e7
commit d930116de2
2 changed files with 33 additions and 0 deletions
+28
View File
@@ -439,6 +439,34 @@ class WorkflowRunApi:
max_steps=max_steps, max_steps=max_steps,
steps_executed=0, steps_executed=0,
) )
if (
record.status is StoredRunStatus.FAILED
and record.latest_checkpoint_id is None
):
# Recovery can fail an admitted execution closed before any
# stopped checkpoint exists: the outcome is deliberately unknown,
# but the durable failure decision and its diagnostics are still
# actionable. Do not route this shape through checkpoint loading
# or fabricate trace/output/state from the failed decision.
try:
max_steps = store.get_admission(run_id).max_steps
except KeyError:
max_steps = None
failure_error = (
record.diagnostics[-1].message if record.diagnostics else None
)
return _run_payload(
deployment=record.environment.deployment,
artifact=record.environment.root_artifact,
status=record.status.value,
run_id=record.id,
resume_readiness=record.resume_readiness.value,
error=failure_error,
diagnostics=record.diagnostics,
max_steps=max_steps,
trace_count=0,
steps_executed=0,
)
record, run = load_stored_run(store, run_id) record, run = load_stored_run(store, run_id)
environment = record.environment environment = record.environment
return _run_payload( return _run_payload(
@@ -761,6 +761,11 @@ async def test_graceful_shutdown_cancel_leaves_executing_for_recovery(
and "external effects may already" in item.message and "external effects may already" in item.message
for item in record.diagnostics for item in record.diagnostics
) )
inspected = await server_b.api.inspect_run(run_id=run_id)
assert inspected["status"] == "failed"
assert inspected["resume_readiness"] == "not_applicable"
assert inspected["error"] is not None
assert "external effects may already" in inspected["error"]
assert len(_entries(root, "hanging", "failed")) == 1 assert len(_entries(root, "hanging", "failed")) == 1
finally: finally:
_gate_open.set() _gate_open.set()