task_create.py 2.4 KB
"""c_task_create (03-C §3.1): task queue entry creation.

U-009 scope: task creation lands `status='queued'`, `assigned_org_node='planner'`
(04-P `p_org_task_lifecycle` start_state, ready for the first `c_org_node_trigger`
call). `c_project_create` is already built in U-002
(project_scaffold.create_project); this module only adds `c_task_create`.

REQ-01's happy case ("依次触发 planner/coder/validator 三个 org_node,task.status
按状态机正确流转") is NOT achievable at this Unit's scope -- it needs
c_org_node_trigger's full implementation (U-010), whose own Done criterion is
almost this exact sentence. development-plan.md's U-009 line claims all three
REQ-01 cases pass here; that's not accurate and is corrected in this session's
notes rather than silently left as-is -- only boundary and failure are real at
U-009, happy completes cumulatively once U-010 lands.
"""

import json
import uuid


class InvalidParamError(Exception):
    """INVALID_PARAM -- 03-C §3.1: empty goal_text, non-existent project_id,
    or a task_type other than 'goal' (bug_fix tasks are created by the Org
    Loop route, not this public-facing endpoint)."""


def create_task(conn, project_id, goal_text, task_type="goal", created_via="api"):
    if not goal_text:
        raise InvalidParamError("goal_text is required")
    if task_type != "goal":
        raise InvalidParamError("task_type must be 'goal' for c_task_create")
    if conn.execute("SELECT 1 FROM project WHERE project_id = ?", (project_id,)).fetchone() is None:
        raise InvalidParamError("project_id does not exist: " + project_id)

    task_id = str(uuid.uuid4())
    try:
        conn.execute(
            "INSERT INTO task "
            "(task_id, project_id, goal_text, task_type, created_via, status, loop_round, assigned_org_node) "
            "VALUES (?, ?, ?, ?, ?, 'queued', 0, 'planner')",
            (task_id, project_id, goal_text, task_type, created_via),
        )
        conn.execute(
            "INSERT INTO execution_event (event_id, project_id, task_id, event_type, payload) "
            "VALUES (?, ?, ?, 'task_status_changed', ?)",
            (str(uuid.uuid4()), project_id, task_id, json.dumps({"from_status": None, "to_status": "queued"})),
        )
    except Exception:
        conn.rollback()
        raise
    conn.commit()  # 03-C §3.1 transaction: task insert + execution_event, same transaction

    return {"task_id": task_id, "status": "queued"}