from __future__ import annotations from datetime import datetime, UTC from app.storage.models import StoredTask class InvalidTransitionError(Exception): """Raised when task workflow transition is invalid.""" def start_task(task: StoredTask) -> StoredTask: """ Transition task from backlog → in_progress. Rules: - Idempotent: if already started, do not change started_at - Cannot start a task that is already done """ # already done → invalid if task.done_at is not None: raise InvalidTransitionError("invalid_transaction") # already started → idempotent (no change) if task.started_at is not None: return task return StoredTask( id=task.id, title=task.title, created_at=task.created_at, started_at=datetime.now(UTC), done_at=task.done_at, ) def complete_task(task: StoredTask) -> StoredTask: """ Transition task from in_progress → done. Rules: - Allowed only if task is started - Idempotent: if already done, do not change done_at """ # not started → invalid if task.started_at is None: raise InvalidTransitionError("invalid_transaction") # already done → idempotent if task.done_at is not None: return task return StoredTask( id=task.id, title=task.title, created_at=task.created_at, started_at=task.started_at, done_at=datetime.now(UTC), )