From 6c4aaa79a23aa4593efccba63d9b869be34052a1 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Wed, 2 Sep 2026 19:12:33 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20QC=E7=AB=9E=E6=80=81=E5=8F=8C=E5=AE=88?= =?UTF-8?q?=E5=8D=AB=E2=80=94=E2=80=94start=5Fqc=E5=B7=B2=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E4=B8=8D=E5=BC=80=E6=96=B0=E8=BD=AE/=E7=A9=BA?= =?UTF-8?q?=E4=BA=A7=E5=87=BA=E4=B8=8D=E7=83=A7=E8=BD=AE+=E5=AF=B9?= =?UTF-8?q?=E8=B4=A6=E5=99=A8=E7=BB=B4=E5=BA=A6=E4=BB=BB=E5=8A=A1=E5=9C=A8?= =?UTF-8?q?=E5=8A=9E=E4=B8=8D=E6=B4=BE=E5=AE=A1=E6=A0=B8(=E5=AE=9E?= =?UTF-8?q?=E6=B5=8Bqualifications=E8=A2=AB=E7=83=A73=E8=BD=AE=E3=80=81cos?= =?UTF-8?q?t=5Fbenefit=E5=AF=B9=E7=A9=BA=E8=A1=A8=E6=89=930)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pipeline_bidding/bid_flow.py | 7 +++++++ pipeline_bidding/bid_qc_capability.py | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/pipeline_bidding/bid_flow.py b/pipeline_bidding/bid_flow.py index 705bb04..a9e9aaf 100644 --- a/pipeline_bidding/bid_flow.py +++ b/pipeline_bidding/bid_flow.py @@ -557,6 +557,13 @@ async def reconcile_project(sor, project_id, project_name=""): for t, _, _, _ in needs_qc: if await _open_qc_type_tasks(sor, project_id, t) > 0: continue + # 竞态守卫(2026-09-02):该维度分析/重做任务在办 → 不派审核。 + # 根治:产出被清空后重做任务还在跑,QC 审核就先派出去对着重写中 + # 的半成品打分(实测 cost_benefit 对空表打 0、qualifications 被连烧两轮)。 + dim = QC_TYPE_TO_DIM.get(t, "") + if dim and await _open_dim_tasks(sor, project_id, dim) > 0: + acts.append("waiting: 维度「%s」分析任务在办,暂不派 %s 审核" % (dim, t)) + continue tid = await create_role_task( sor, project_id, R_QC, "%s 解析产出契合度审核(%s)" % (pname, t), diff --git a/pipeline_bidding/bid_qc_capability.py b/pipeline_bidding/bid_qc_capability.py index f88adfd..c3844ee 100644 --- a/pipeline_bidding/bid_qc_capability.py +++ b/pipeline_bidding/bid_qc_capability.py @@ -119,6 +119,32 @@ async def start_qc(qc_type, project_id="", who=None, agent_id=None, task_id=""): "AND fit_score IS NULL ORDER BY created_at DESC LIMIT 1", {"p": project_id, "t": qc_type}) await sor.sqlExe("COMMIT", {}) + # 已通过守卫(2026-09-02):最新一轮已放行 → 不再开新轮。 + # 根治:任务被引擎通用门禁弹回重跑时再次 start_qc 会白白烧掉一轮 + # (qualifications 实测:第2轮8.80已过,弹回重跑开第3轮对重写中的表打5.6)。 + # 产出若被 QC 清空重做,对账器只在重做完成后才重新派审核,此处不会误挡。 + last_r = await sor.sqlExe( + "SELECT round, fit_score, passed FROM bid_qc_reviews WHERE project_id=${p}$ AND qc_type=${t}$ " + "ORDER BY round DESC LIMIT 1", {"p": project_id, "t": qc_type}) + await sor.sqlExe("COMMIT", {}) + if last_r and not open_r and str(rec_to_dict(last_r[0]).get("passed")) == "1": + _lr = rec_to_dict(last_r[0]) + return True, {"status": "already_passed", "qc_type": qc_type, + "round": _lr.get("round"), "fit_score": _lr.get("fit_score"), + "message": "该类型第 %s 轮已通过契合度审核(%.2f 分 > 通过分),无需重审。" + "直接完成任务即可。" % (_lr.get("round"), to_float(_lr.get("fit_score")))} + # 空产出守卫(2026-09-02):产出被 QC 清空、重做未完成 → 不开新轮。 + # 根治:QC 审核任务比分析重做任务先跑时对着空表开轮打 0 分,白白烧一轮 + # (cost_benefit 实测:第2轮对着零记录表打 0.00)。 + _cnt = await sor.sqlExe( + "SELECT COUNT(*) AS c FROM " + QC_OUTPUT_TABLE[qc_type] + " WHERE project_id=${p}$", + {"p": project_id}) + await sor.sqlExe("COMMIT", {}) + if not open_r and to_int(getattr(_cnt[0], "c", 0) if _cnt else 0) == 0: + return True, {"status": "no_output", "qc_type": qc_type, + "message": "%s 当前无产出记录(被 QC 清空待重做或重做未完成)," + "不开评审轮次。请等待分析重做任务落库后再审," + "本轮任务直接交付说明等待原因即可。" % qc_type} if open_r: rid = getattr(open_r[0], "id", "") rnd = to_int(getattr(open_r[0], "round", 1), 1)