Finish STATE-WP-0069: retire legacy completion event and DELETE /workstreams
Stop dual-publishing org.statehub.workstream.completed; return 410 Gone for
legacy DELETE /workstreams/{id}. Migrate fix-consistency, MCP adhoc bootstrap,
and dashboard token summary to /workplans/. Add legacy-meter evidence capture
script and pytest snapshot; update docs and close out the workplan.
This commit is contained in:
parent
b659ff8d13
commit
e0c954d098
13 changed files with 404 additions and 149 deletions
|
|
@ -23,12 +23,8 @@ from api.schemas.workplan import (
|
|||
WorkplanUpdate,
|
||||
)
|
||||
from api.services.lifecycle import transition_workplan_status
|
||||
from api.services.legacy_compat import mark_legacy_response
|
||||
from api.services.legacy_meter import (
|
||||
LegacyUsageIdentity,
|
||||
identity_from_request,
|
||||
record_legacy_usage,
|
||||
)
|
||||
from api.services.legacy_compat import legacy_response_headers, mark_legacy_response
|
||||
from api.services.legacy_meter import identity_from_request, record_legacy_usage
|
||||
from api.workplan_status import (
|
||||
is_supported_workplan_status,
|
||||
normalize_workplan_status,
|
||||
|
|
@ -47,7 +43,6 @@ _INDEX_REFRESH_TASK: asyncio.Task | None = None
|
|||
_INDEX_LAST_ERROR: str | None = None
|
||||
|
||||
_LEGACY_OWNER = "state-hub.api"
|
||||
_COMPLETED_WORKSTREAM_EVENT = "org.statehub.workstream.completed"
|
||||
_COMPLETED_WORKPLAN_EVENT = "org.statehub.workplan.completed"
|
||||
|
||||
|
||||
|
|
@ -111,27 +106,6 @@ async def _meter_legacy_route(
|
|||
logger.warning("legacy-meter failed to record %s", interface_key, exc_info=True)
|
||||
|
||||
|
||||
async def _meter_legacy_event(
|
||||
*,
|
||||
session: AsyncSession,
|
||||
subject: str,
|
||||
replacement_ref: str,
|
||||
) -> None:
|
||||
try:
|
||||
await record_legacy_usage(
|
||||
session,
|
||||
interface_key=f"event_subject:{subject}",
|
||||
interface_kind="event_subject",
|
||||
replacement_ref=replacement_ref,
|
||||
owner_component="state-hub.events",
|
||||
replacement_verified=True,
|
||||
identity=LegacyUsageIdentity(component_key="state-hub.events"),
|
||||
)
|
||||
except Exception:
|
||||
await session.rollback()
|
||||
logger.warning("legacy-meter failed to record event subject %s", subject, exc_info=True)
|
||||
|
||||
|
||||
async def _list_workplans(
|
||||
*,
|
||||
topic_id: uuid.UUID | None,
|
||||
|
|
@ -377,7 +351,6 @@ async def _publish_completion_events(wp: Workplan, session: AsyncSession) -> Non
|
|||
_COMPLETED_WORKPLAN_EVENT,
|
||||
attributes={
|
||||
"workplan_id": str(wp.id),
|
||||
"legacy_workstream_id": str(wp.id),
|
||||
"slug": wp.slug,
|
||||
"title": wp.title,
|
||||
"topic_id": str(wp.topic_id) if wp.topic_id else None,
|
||||
|
|
@ -387,24 +360,6 @@ async def _publish_completion_events(wp: Workplan, session: AsyncSession) -> Non
|
|||
)
|
||||
asyncio.create_task(publish_event(_COMPLETED_WORKPLAN_EVENT, workplan_envelope))
|
||||
|
||||
await _meter_legacy_event(
|
||||
session=session,
|
||||
subject=_COMPLETED_WORKSTREAM_EVENT,
|
||||
replacement_ref=_COMPLETED_WORKPLAN_EVENT,
|
||||
)
|
||||
legacy_envelope = EventEnvelope.new(
|
||||
_COMPLETED_WORKSTREAM_EVENT,
|
||||
attributes={
|
||||
"workstream_id": str(wp.id),
|
||||
"slug": wp.slug,
|
||||
"title": wp.title,
|
||||
"topic_id": str(wp.topic_id) if wp.topic_id else None,
|
||||
"repo_id": str(wp.repo_id) if wp.repo_id else None,
|
||||
"repo_goal_id": str(wp.repo_goal_id) if wp.repo_goal_id else None,
|
||||
},
|
||||
)
|
||||
asyncio.create_task(publish_event(_COMPLETED_WORKSTREAM_EVENT, legacy_envelope))
|
||||
|
||||
|
||||
@router.get("/", response_model=list[WorkplanRead])
|
||||
async def list_workstreams(
|
||||
|
|
@ -581,21 +536,26 @@ async def update_workplan(
|
|||
return await _update_workplan(workplan_id=workplan_id, body=body, session=session)
|
||||
|
||||
|
||||
@router.delete("/{workstream_id}", response_model=WorkplanRead)
|
||||
@router.delete("/{workstream_id}", status_code=status.HTTP_410_GONE)
|
||||
async def archive_workstream(
|
||||
request: Request,
|
||||
response: Response,
|
||||
workstream_id: uuid.UUID,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> Workplan:
|
||||
) -> None:
|
||||
replacement_ref = "DELETE /workplans/{workplan_id}"
|
||||
await _meter_legacy_route(
|
||||
session=session,
|
||||
request=request,
|
||||
response=response,
|
||||
interface_key=_legacy_key("DELETE", "/workstreams/{workstream_id}"),
|
||||
replacement_ref="/workplans/{workplan_id}",
|
||||
replacement_ref=replacement_ref,
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_410_GONE,
|
||||
detail="Legacy DELETE /workstreams/{workstream_id} retired; use DELETE /workplans/{workplan_id}",
|
||||
headers=legacy_response_headers(replacement_ref),
|
||||
)
|
||||
return await _archive_workplan(workplan_id=workstream_id, session=session)
|
||||
|
||||
|
||||
@workplan_router.delete("/{workplan_id}", response_model=WorkplanRead)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue