mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
[F016,F017] choreographer: surface invalid_state instead of None.status 500 on submit_root / i_am_blocked
Both verbs compose a single atomic action whose None return (the verb's own result) flowed out of run_intent and was dereferenced as t.status, HTTP 500-ing with no actionable rejection: - F016 submit_root: submit_for_review returns None when the root->master PR was already opened / the task raced out of in_progress. Post-runner None-guard extracted into _submit_root_finalize -> invalid_state (re-fetch; if awaiting_pr_review the PR is open, wait for reviewer; else re-delegate fixes and retry) instead of None.status. - F017 i_am_blocked: escalate returns None in four cases (no task, no agent, no resolvable escalation-target slug, no target agent row) e.g. a developer whose role has no PM above it. _run_i_am_blocked_intent now guards updated is None -> (t, invalid_state rejection) with remediation (re-fetch + escalate to CEO directly / retry) instead of the caller deref'ing None.status -> 500 + respawn-loop. TDD red->green; ruff + mypy clean; gateway suite green (58 passed).
This commit is contained in:
@@ -404,3 +404,29 @@ async def test_pr_pass_does_not_capture_head_sha() -> None:
|
||||
# pr_pass path never calls _capture_pr_head_sha, so head_sha is absent
|
||||
# from the kwargs (the default None is not passed).
|
||||
assert "head_sha" not in record_spy.call_args.kwargs
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# F016 — submit_root must not 500 when submit_for_review returns None
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_root_invalid_state_when_submit_for_review_returns_none() -> None:
|
||||
"""F016: submit_for_review returns None when the root->master PR was already
|
||||
opened (the task raced out of in_progress, or a prior call already
|
||||
transitioned it). create_root_pr already ran as the pre-side-effect, so the
|
||||
PR exists, but the transition did not happen. submit_root must surface an
|
||||
invalid_state envelope, not dereference None.status and 500."""
|
||||
c, main_pm_id, root_task_id = _resubmit_root(notes_structured=None)
|
||||
# The transition did not happen (PR already opened / task raced).
|
||||
c.task.submit_for_review.return_value = None
|
||||
|
||||
env = await c.submit_root(
|
||||
main_pm_id, root_task_id, notes="re-submit; transition returned nothing"
|
||||
)
|
||||
|
||||
assert env.error is not None, env.as_dict()
|
||||
assert env.error == "invalid_state"
|
||||
remediate = env.remediate or ""
|
||||
assert "evidence" in remediate.lower() or "re-fetch" in remediate.lower()
|
||||
|
||||
Reference in New Issue
Block a user