From ca0cfc29de8446a210371555f399255573c88712 Mon Sep 17 00:00:00 2001 From: ymq Date: Fri, 21 Aug 2026 13:03:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(sdlc):=20=E8=BF=AD=E4=BB=A3=E7=BA=A7=20req?= =?UTF-8?q?uirement=20=E4=BB=BB=E5=8A=A1=E6=9F=A5=E9=87=8D=E2=80=94?= =?UTF-8?q?=E2=80=94=E5=90=8C=E4=B8=80=E8=BF=AD=E4=BB=A3=E4=B8=8D=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=88=9B=E5=BB=BA=E9=9C=80=E6=B1=82=E5=88=86=E6=9E=90?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pipeline_service/sdlc_ability.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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,