fix(status-enum): add paused to ProjectStatus, validate, fix progress
Drift-audit Group 6 + Group 5 #6 (enum-extension / status drift): - ProjectStatus gains 'paused' — routes and frontend already treated it as first-class, but the enum (the source of truth) omitted it and the error strings lied. A future CHECK derived from the enum would have rejected existing paused rows. - create_project/update_project now validate status via ProjectStatus at the service layer (canonical gate; notes.status has no DB CHECK), so the MCP create/update_project path can't persist a typo'd status. MCP docstrings realigned to the 4-value domain; route error strings corrected. - get_milestone_progress: cancelled tasks are excluded from the percent denominator (and now reported in status_counts), so a milestone whose only open task was cancelled reaches 100% instead of stalling below it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,7 @@ async def create_project_route():
|
||||
return jsonify({"error": "title is required"}), 400
|
||||
status = data.get("status", "active")
|
||||
if status not in ("active", "paused", "completed", "archived"):
|
||||
return jsonify({"error": "status must be 'active', 'completed', or 'archived'"}), 400
|
||||
return jsonify({"error": "status must be 'active', 'paused', 'completed', or 'archived'"}), 400
|
||||
project = await create_project(
|
||||
uid,
|
||||
title=data["title"],
|
||||
@@ -90,7 +90,7 @@ async def update_project_route(project_id: int):
|
||||
allowed = {"title", "description", "goal", "status", "color"}
|
||||
fields = {k: (v if v is not None else "") for k, v in data.items() if k in allowed}
|
||||
if "status" in fields and fields["status"] not in ("active", "paused", "completed", "archived"):
|
||||
return jsonify({"error": "status must be 'active', 'completed', or 'archived'"}), 400
|
||||
return jsonify({"error": "status must be 'active', 'paused', 'completed', or 'archived'"}), 400
|
||||
project = await update_project(uid, project_id, **fields)
|
||||
if project is None:
|
||||
return not_found("Project")
|
||||
|
||||
Reference in New Issue
Block a user