feat: add workplan aliases and legacy meter

Adds preferred workplan REST/event surfaces, legacy-meter telemetry and weekly review summaries, documentation/dashboard terminology updates, dashboard API loading fixes, and close-out sync for STATE-WP-0052 and STATE-WP-0054.
This commit is contained in:
2026-06-04 08:25:31 +02:00
parent 355f80b078
commit 166aedfa8d
43 changed files with 1851 additions and 145 deletions

View File

@@ -1,6 +1,6 @@
import uuid
from fastapi import APIRouter, Depends, HTTPException, Query, status
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Response, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -27,6 +27,7 @@ from api.services.execution_queue import (
queue_sort_key,
workstream_blockers,
)
from api.routers.workstreams import _legacy_key, _meter_legacy_route
from api.workplan_status import CLOSED_WORKSTREAM_STATUSES, normalize_workstream_status
router = APIRouter(prefix="/execution", tags=["execution"])
@@ -43,15 +44,15 @@ async def execution_semantics() -> ExecutionSemantics:
)
@router.patch("/workstreams/{workstream_id}/intent", response_model=ExecutionIntentRead)
async def update_execution_intent(
async def _update_execution_intent(
*,
workstream_id: uuid.UUID,
body: ExecutionIntentUpdate,
session: AsyncSession = Depends(get_session),
session: AsyncSession,
) -> ExecutionIntentRead:
ws = await session.get(Workstream, workstream_id)
if ws is None:
raise HTTPException(status_code=404, detail="Workstream not found")
raise HTTPException(status_code=404, detail="Workplan not found")
for field, value in body.model_dump(exclude_unset=True).items():
setattr(ws, field, value)
@@ -60,6 +61,33 @@ async def update_execution_intent(
return _intent_read(ws)
@router.patch("/workstreams/{workstream_id}/intent", response_model=ExecutionIntentRead)
async def update_execution_intent(
request: Request,
response: Response,
workstream_id: uuid.UUID,
body: ExecutionIntentUpdate,
session: AsyncSession = Depends(get_session),
) -> ExecutionIntentRead:
await _meter_legacy_route(
session=session,
request=request,
response=response,
interface_key=_legacy_key("PATCH", "/execution/workstreams/{workstream_id}/intent"),
replacement_ref="/execution/workplans/{workplan_id}/intent",
)
return await _update_execution_intent(workstream_id=workstream_id, body=body, session=session)
@router.patch("/workplans/{workplan_id}/intent", response_model=ExecutionIntentRead)
async def update_workplan_execution_intent(
workplan_id: uuid.UUID,
body: ExecutionIntentUpdate,
session: AsyncSession = Depends(get_session),
) -> ExecutionIntentRead:
return await _update_execution_intent(workstream_id=workplan_id, body=body, session=session)
@router.get("/workplan-stack", response_model=list[WorkplanQueueItem])
async def workplan_stack(
include_manual: bool = Query(True),