fix: post-finale completeness sweep — routing surface, provider config, budgets, compose env, interactive exemption (#661)

This commit is contained in:
Renzo F
2026-07-23 09:41:27 +02:00
committed by GitHub
parent 21d6730400
commit d4b7e1e7b8
45 changed files with 2064 additions and 256 deletions
+165
View File
@@ -0,0 +1,165 @@
"""Task.budget_usd / Project.monthly_budget_usd validation (#654).
The task-budgets feature's own design says "0 rejected — a zero budget
silently blocks everything" (every claim is refused from the first tick),
so every schema that can set these fields must reject 0 and negative values
at the pydantic boundary — a 422, never a stored self-DoS. Null ("no cap")
stays valid throughout. Mirrors test_project_sandbox_services.py's style
(domain-model `pytest.raises(ValidationError)` coverage).
"""
from __future__ import annotations
from uuid import uuid4
import pytest
from pydantic import ValidationError
from roboco.models.base import Team
from roboco.models.project import Project, ProjectCreate, ProjectUpdate
from roboco.models.task import Task, TaskUpdate
def _task(budget_usd: float | None = None) -> Task:
return Task(
title="Add user lookup endpoint",
description="Add GET /v1/users/{id} returning user JSON.",
acceptance_criteria=["returns 404 for unknown user"],
created_by=uuid4(),
team=Team.BACKEND,
budget_usd=budget_usd,
)
def _project(monthly_budget_usd: float | None = None) -> Project:
return Project(
name="P",
slug="p",
git_url="https://example.com/r.git",
assigned_cell=Team.BACKEND,
created_by=uuid4(),
monthly_budget_usd=monthly_budget_usd,
)
# ---------------------------------------------------------------------------
# Task.budget_usd
# ---------------------------------------------------------------------------
def test_task_defaults_budget_usd_to_none() -> None:
assert _task().budget_usd is None
def test_task_accepts_positive_budget_usd() -> None:
budget = 12.5
assert _task(budget_usd=budget).budget_usd == budget
def test_task_rejects_zero_budget_usd() -> None:
with pytest.raises(ValidationError, match="budget_usd"):
_task(budget_usd=0)
def test_task_rejects_negative_budget_usd() -> None:
with pytest.raises(ValidationError, match="budget_usd"):
_task(budget_usd=-5)
# ---------------------------------------------------------------------------
# roboco.models.task.TaskUpdate.budget_usd (domain update model)
# ---------------------------------------------------------------------------
def test_task_update_accepts_null_budget_usd() -> None:
assert TaskUpdate(budget_usd=None).budget_usd is None
def test_task_update_accepts_positive_budget_usd() -> None:
budget = 3.0
assert TaskUpdate(budget_usd=budget).budget_usd == budget
def test_task_update_rejects_zero_budget_usd() -> None:
with pytest.raises(ValidationError, match="budget_usd"):
TaskUpdate(budget_usd=0)
def test_task_update_rejects_negative_budget_usd() -> None:
with pytest.raises(ValidationError, match="budget_usd"):
TaskUpdate(budget_usd=-1)
# ---------------------------------------------------------------------------
# Project.monthly_budget_usd
# ---------------------------------------------------------------------------
def test_project_defaults_monthly_budget_usd_to_none() -> None:
assert _project().monthly_budget_usd is None
def test_project_accepts_positive_monthly_budget_usd() -> None:
cap = 100.0
assert _project(monthly_budget_usd=cap).monthly_budget_usd == cap
def test_project_rejects_zero_monthly_budget_usd() -> None:
with pytest.raises(ValidationError, match="monthly_budget_usd"):
_project(monthly_budget_usd=0)
def test_project_rejects_negative_monthly_budget_usd() -> None:
with pytest.raises(ValidationError, match="monthly_budget_usd"):
_project(monthly_budget_usd=-5)
# ---------------------------------------------------------------------------
# ProjectCreate.monthly_budget_usd
# ---------------------------------------------------------------------------
def test_project_create_accepts_null_monthly_budget_usd() -> None:
assert (
ProjectCreate(
name="P",
slug="p",
git_url="https://example.com/r.git",
assigned_cell=Team.BACKEND,
).monthly_budget_usd
is None
)
def test_project_create_rejects_zero_monthly_budget_usd() -> None:
with pytest.raises(ValidationError, match="monthly_budget_usd"):
ProjectCreate(
name="P",
slug="p",
git_url="https://example.com/r.git",
assigned_cell=Team.BACKEND,
monthly_budget_usd=0,
)
# ---------------------------------------------------------------------------
# ProjectUpdate.monthly_budget_usd
# ---------------------------------------------------------------------------
def test_project_update_accepts_null_monthly_budget_usd() -> None:
assert ProjectUpdate(monthly_budget_usd=None).monthly_budget_usd is None
def test_project_update_accepts_positive_monthly_budget_usd() -> None:
cap = 50.0
assert ProjectUpdate(monthly_budget_usd=cap).monthly_budget_usd == cap
def test_project_update_rejects_zero_monthly_budget_usd() -> None:
with pytest.raises(ValidationError, match="monthly_budget_usd"):
ProjectUpdate(monthly_budget_usd=0)
def test_project_update_rejects_negative_monthly_budget_usd() -> None:
with pytest.raises(ValidationError, match="monthly_budget_usd"):
ProjectUpdate(monthly_budget_usd=-5)