fix(status-enum): add paused to ProjectStatus, validate, fix progress
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 46s
CI & Build / Python tests (push) Successful in 50s
CI & Build / Build & push image (push) Successful in 1m14s

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:
2026-06-02 19:16:45 -04:00
co-authored by Claude Opus 4.8
parent 4a220db513
commit c016bd664e
5 changed files with 31 additions and 7 deletions
+7 -1
View File
@@ -155,8 +155,13 @@ async def get_milestone_progress(milestone_id: int) -> dict:
status_counts[status] = count
total = sum(status_counts.values())
cancelled = status_counts.get("cancelled", 0)
completed = status_counts.get("done", 0)
pct = round(completed / total * 100, 1) if total > 0 else 0.0
# Cancelled tasks are resolved work, not pending — exclude them from the
# percent-complete denominator so a milestone whose only open task was
# cancelled still reaches 100% (and auto-collapses) instead of stalling.
active_total = total - cancelled
pct = round(completed / active_total * 100, 1) if active_total > 0 else 0.0
return {
"total": total,
@@ -166,6 +171,7 @@ async def get_milestone_progress(milestone_id: int) -> dict:
"todo": status_counts.get("todo", 0),
"in_progress": status_counts.get("in_progress", 0),
"done": status_counts.get("done", 0),
"cancelled": cancelled,
},
}