STATE-WP-0069 T04: meter workstream_id query-param aliases
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 3s

Add legacy_compat helper and Deprecation headers when callers filter
/tasks, /decisions, /token-events, or /execution/launch-requests with
workstream_id. Preferred workplan_id filters are unchanged. Route removal
remains gated on legacy-meter zero-usage windows.
This commit is contained in:
tegwick 2026-07-08 21:32:14 +02:00
parent b2b72b7327
commit 793a39a1a4
8 changed files with 181 additions and 15 deletions

View file

@ -1,7 +1,7 @@
import uuid
from datetime import date
from fastapi import APIRouter, Depends, HTTPException, Query, status
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Response, status
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
@ -18,6 +18,7 @@ from api.schemas.task import (
TaskStatusBulkSyncRead,
TaskUpdate,
)
from api.services.legacy_compat import meter_legacy_query_param
from api.services.lifecycle import status_value, transition_task_status
from api.task_status import normalize_task_status
@ -26,6 +27,8 @@ router = APIRouter(prefix="/tasks", tags=["tasks"])
@router.get("/", response_model=list[TaskRead])
async def list_tasks(
request: Request,
response: Response,
workplan_id: uuid.UUID | None = None,
workstream_id: uuid.UUID | None = None,
status: str | None = None,
@ -37,6 +40,15 @@ async def list_tasks(
offset: int = Query(0, ge=0),
session: AsyncSession = Depends(get_session),
) -> list[Task]:
if workstream_id is not None and workplan_id is None:
await meter_legacy_query_param(
session=session,
request=request,
response=response,
method="GET",
route="/tasks/",
replacement_ref="/tasks/?workplan_id=<workplan_id>",
)
q = select(Task)
scope_id = workplan_id or workstream_id
if scope_id:
@ -62,11 +74,22 @@ async def list_tasks(
@router.get("/counts", response_model=list[TaskCountRead])
async def count_tasks(
request: Request,
response: Response,
workplan_id: uuid.UUID | None = None,
workstream_id: uuid.UUID | None = None,
status: str | None = None,
session: AsyncSession = Depends(get_session),
) -> list[TaskCountRead]:
if workstream_id is not None and workplan_id is None:
await meter_legacy_query_param(
session=session,
request=request,
response=response,
method="GET",
route="/tasks/counts",
replacement_ref="/tasks/counts?workplan_id=<workplan_id>",
)
q = select(Task.workplan_id, Task.status, func.count()).group_by(Task.workplan_id, Task.status)
scope_id = workplan_id or workstream_id
if scope_id: