diff --git a/pipeline_service/sdlc_ability.py b/pipeline_service/sdlc_ability.py index 9fbe110..6fd5793 100644 --- a/pipeline_service/sdlc_ability.py +++ b/pipeline_service/sdlc_ability.py @@ -407,6 +407,22 @@ async def _h_create_task(sor, p, ctx): if iteration_name: params["iteration_id"] = iteration_name + # 迭代级查重:requirement 是迭代的初始任务,同一迭代内不应重复创建。 + # 判断粒度是「迭代」而非「项目」——每个迭代有自己独立的初始任务与任务链, + # 新迭代(start_next_iteration)才需要新的需求分析任务。 + if role == 'agent.requirement' and iteration_name: + dup_recs = await sor.sqlExe( + "SELECT id, title, state FROM pipeline_tasks WHERE tenant_id=${pid}$ " + "AND role='agent.requirement' AND state != 'cancelled' " + "AND JSON_UNQUOTE(JSON_EXTRACT(params,'$.iteration_id'))=${nm}$ LIMIT 1", + {"pid": pid, "nm": iteration_name}) + if dup_recs: + d = dup_recs[0] + return (f"⚠️ 拒绝创建:当前迭代「{iteration_name}」已有需求分析任务「{getattr(d, 'title', '')}」" + f"(状态 {getattr(d, 'state', '')})。需求分析是迭代的初始任务,同一迭代不应重复创建;" + f"请 list_tasks 查看现状、更新现有需求或推进下一阶段;" + f"若要新起一轮需求分析,请用 start_next_iteration 开启新迭代。") + await sor.C("pipeline_tasks", { "id": tid, "tenant_id": pid, "pipeline_id": "role_task", "owner_id": ctx.get("user_id") or "user", "title": title,