[f8480831] Batch B: extract route helpers in remaining smaller-offender route files (#760)

* [f8480831] refactor(api): extract route-layer helpers into services/schemas/utils (batch B)

Moves 28 non-@router-decorated helper functions out of 15 route files
(optimal, project, release, dashboard, pitch, x, docs, git, playbooks,
product, provider, research, secretary, system, work_session) into
their paired services module (DB/service-calling helpers), the route's
schemas module as a converter (pure response/request shaping, mirroring
the existing project_to_response/assignment_to_response pattern), or
roboco/utils/converters.py (pure generic helpers). Adds two small
shared role-check helpers to api/deps.py (require_auditor_or_ceo,
require_role_in) for endpoint-specific role gates that had no existing
home. Placement-only: no route paths, schemas, or observable behavior
changed. Fixes the handful of tests that imported the old private
helper names directly.

* [f8480831] docs(map): document Batch B route-helper relocation in api-routes-schemas.md

* [f8480831] docs(map): add Key Symbols rows for require_auditor_or_ceo/require_role_in

---------

Co-authored-by: Backend Developer 2 <be-dev-2@roboco.tech>
Co-authored-by: Backend Documenter <be-doc@roboco.tech>
This commit is contained in:
roboco-app[bot]
2026-07-31 20:23:10 +00:00
committed by GitHub
co-authored by Backend Developer 2 Backend Documenter
parent 109b4d4d82
commit 7804e0fafa
37 changed files with 778 additions and 717 deletions
+6 -6
View File
@@ -14,7 +14,6 @@ import pytest_asyncio
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from roboco.api.deps import get_agent_context, get_db
from roboco.api.routes.git import _translate_error
from roboco.api.routes.git import router as git_router
from roboco.db.tables import AgentTable, ProjectTable
from roboco.exceptions import GitCommandError, GitTimeoutError
@@ -26,6 +25,7 @@ from roboco.services.base import (
UnauthorizedError,
ValidationError,
)
from roboco.services.git import translate_git_error
if TYPE_CHECKING:
from collections.abc import AsyncGenerator, AsyncIterator
@@ -215,23 +215,23 @@ async def test_status_not_found(git_client: dict) -> None:
@pytest.mark.asyncio
async def test_status_git_timeout_directly() -> None:
"""Exercise _translate_error's GitTimeoutError branch directly.
"""Exercise translate_git_error's GitTimeoutError branch directly.
The route uses `except ServiceError as e` from services.base, but
GitTimeoutError extends roboco.exceptions.ServiceError (different
class), so it never enters _translate_error in practice. We invoke
class), so it never enters translate_git_error in practice. We invoke
the helper directly to cover the branch.
"""
err = GitTimeoutError("git status", 10)
http_exc = _translate_error(err)
http_exc = translate_git_error(err)
assert http_exc.status_code == HTTPStatus.GATEWAY_TIMEOUT
@pytest.mark.asyncio
async def test_status_git_command_error_directly() -> None:
"""Direct invocation of _translate_error's GitCommandError branch."""
"""Direct invocation of translate_git_error's GitCommandError branch."""
err = GitCommandError("git status", "stderr")
http_exc = _translate_error(err)
http_exc = translate_git_error(err)
assert http_exc.status_code == HTTPStatus.INTERNAL_SERVER_ERROR