feat(sdlc): 判断粒度落到迭代——create_task 迭代级查重 + diagnose_project 迭代级诊断 + prompt 迭代约束
1. _h_create_task:创建 requirement 任务前查「当前迭代」是否已有非 cancelled 的 requirement 任务(迭代的初始任务),有则拒绝重复创建,避免人事项目2 那种 需求分析完成后又重复启动需求分析。 2. _h_diagnose_project:诊断单位从「项目」改为「当前迭代」(in_progress), 按 iteration_id 过滤统计/列出任务,避免多迭代并存时诊断结果混在一起。 3. SDL_PROMPT:加「迭代粒度」约束——每个迭代独立初始任务+任务链, 创建 requirement 前先查重、诊断/派发/推进都以当前迭代为单位。
This commit is contained in:
parent
ca0cfc29de
commit
9c4f3deea6
@ -217,6 +217,11 @@ SDL_PROMPT = """你是「开发产线」的驾驶舱 agent,负责软件项目
|
||||
- 除功能需求外,需求阶段还要明确部署环境需求:测试环境 + 生产环境的资源规格、依赖服务、端口、环境变量、高可用/备份/域名证书/监控告警等。
|
||||
- 用户未提供时,在会话中逐步追问明确(用 ask_user / list_questions),不要跳过;明确后再创建 requirement 任务。
|
||||
|
||||
## 迭代粒度(重要)
|
||||
- 每个迭代有自己独立的初始任务(requirement 需求分析)和完整任务链(requirement → design → develop → deploy_test → test → deploy_prod)。
|
||||
- 创建 requirement 任务前,必须先 list_tasks 查「当前迭代」是否已有需求分析任务;同一迭代已有(含 approved/completed)→ 更新现有需求或推进下一阶段,禁止重复创建;只有新迭代(start_next_iteration)才需要新的初始任务。
|
||||
- 诊断卡点、派发任务、推进项目都以「当前迭代」为单位(diagnose_project 已按当前迭代统计),不要混着整个项目看。
|
||||
|
||||
## 典型场景(帮助判断何时用哪个工具,非强制)
|
||||
- 用户提出新的开发需求/功能("实现XX""XX系统要做XX")→ 先确认部署环境需求,再用 create_task 创建任务(可按 requirement→design→develop 拆分),再 start_agents 启动。**单个任务不要过大**:涉及多个模块/多个独立交付单元时按模块拆小(每个模块一个 develop 任务),禁止一次性派发「实现全部 N 个模块/全部表契约/脚手架+DDL 全套」这种巨型任务。**模块化原则**:模块划分+模块间依赖关系由 design 阶段设计师完成(需求阶段只识别应用/部署单元,PM 按设计师模块清单派发);apppublic/sqlor/ahserver/accounting/appbase/rbac 等基础模块已存在可直接引用,不必再开发。
|
||||
- 用户问进展/状态 → list_tasks / diagnose_project / check_progress。
|
||||
@ -554,10 +559,18 @@ async def _h_diagnose_project(sor, p, ctx):
|
||||
if not pid:
|
||||
return "请先切换到项目"
|
||||
|
||||
# 迭代级诊断:诊断单位是「当前迭代」(in_progress),而非整个项目。
|
||||
# 项目只是迭代的容器;PM 诊断卡点、派发任务、推进都以当前迭代为单位。
|
||||
from .iteration_capability import get_current_iteration
|
||||
cur_iter = await get_current_iteration(sor, pid)
|
||||
iter_name = cur_iter.get('iteration_name', '') if cur_iter else ''
|
||||
iter_cond = " AND JSON_UNQUOTE(JSON_EXTRACT(params,'$.iteration_id'))=${nm}$ " if iter_name else ""
|
||||
iter_bind = {"nm": iter_name} if iter_name else {}
|
||||
|
||||
async def _cnt(state):
|
||||
recs = await sor.sqlExe(
|
||||
"SELECT COUNT(*) as c FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state=${st}$",
|
||||
{"pid": pid, "st": state})
|
||||
"SELECT COUNT(*) as c FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state=${st}$" + iter_cond,
|
||||
{"pid": pid, "st": state, **iter_bind})
|
||||
return getattr(recs[0], "c", 0) if recs else 0
|
||||
|
||||
sc = await _cnt("submitted")
|
||||
@ -575,7 +588,7 @@ async def _h_diagnose_project(sor, p, ctx):
|
||||
pass
|
||||
|
||||
lines = [
|
||||
"项目诊断:",
|
||||
f"项目诊断(当前迭代:{iter_name or '无 in_progress 迭代(回退项目级)'}):",
|
||||
f"- 待执行: {sc}",
|
||||
f"- 运行中: {rc}",
|
||||
f"- 待审核: {vc}",
|
||||
@ -585,15 +598,15 @@ async def _h_diagnose_project(sor, p, ctx):
|
||||
|
||||
if fc:
|
||||
failed_rows = await sor.sqlExe(
|
||||
"SELECT id, title, role FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state='failed' ORDER BY created_at DESC LIMIT 10",
|
||||
{"pid": pid})
|
||||
"SELECT id, title, role FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state='failed'" + iter_cond + "ORDER BY created_at DESC LIMIT 10",
|
||||
{"pid": pid, **iter_bind})
|
||||
lines.append("失败任务:")
|
||||
for fr in (failed_rows or []):
|
||||
lines.append(f" - [{getattr(fr, 'role', '?')}] {getattr(fr, 'title', '')} (id={getattr(fr, 'id', '')})")
|
||||
if sc:
|
||||
submitted_rows = await sor.sqlExe(
|
||||
"SELECT id, title, role FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state='submitted' ORDER BY created_at ASC LIMIT 10",
|
||||
{"pid": pid})
|
||||
"SELECT id, title, role FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state='submitted'" + iter_cond + "ORDER BY created_at ASC LIMIT 10",
|
||||
{"pid": pid, **iter_bind})
|
||||
lines.append("待执行任务:")
|
||||
for sr in (submitted_rows or []):
|
||||
lines.append(f" - [{getattr(sr, 'role', '?')}] {getattr(sr, 'title', '')} (id={getattr(sr, 'id', '')})")
|
||||
@ -601,9 +614,8 @@ async def _h_diagnose_project(sor, p, ctx):
|
||||
running_rows = await sor.sqlExe(
|
||||
"SELECT id, title, role, claimed_by, "
|
||||
"TIMESTAMPDIFF(MINUTE, updated_at, NOW()) AS mins "
|
||||
"FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state='running' "
|
||||
"ORDER BY updated_at ASC LIMIT 10",
|
||||
{"pid": pid})
|
||||
"FROM pipeline_tasks WHERE tenant_id=${pid}$ AND state='running'" + iter_cond + "ORDER BY updated_at ASC LIMIT 10",
|
||||
{"pid": pid, **iter_bind})
|
||||
lines.append("运行中任务:")
|
||||
for rr in (running_rows or []):
|
||||
rrole = getattr(rr, 'role', '?')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user