From 0f23c0d8de213e6b24230dbaff9479d4fbc385c0 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Tue, 15 Sep 2026 21:51:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(bid=5Fflow):=20=E4=B8=89=E8=BF=9E=E4=BF=AE(?= =?UTF-8?q?2026-09-15=E7=94=98=E8=82=83=E9=A1=B9=E7=9B=AE=E5=AE=9E?= =?UTF-8?q?=E6=B5=8B)=E2=80=94=E2=80=94=E2=91=A0audit=5Flog=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=88=97=E5=90=8Dupdated=5Fat=E2=86=92created=5Fat(?= =?UTF-8?q?=E8=A1=A8=E5=8F=AA=E6=9C=89created=5Fat,1054=E5=B4=A9=E6=8E=89?= =?UTF-8?q?=E6=95=B4=E4=B8=AAreconcile=5Fproject,=E7=AC=AC3=E8=BD=AE?= =?UTF-8?q?=E5=A4=8D=E5=AE=A1=E6=B4=BE=E5=8F=91=E8=B7=AF=E5=BE=8412?= =?UTF-8?q?=E5=A4=A9=E9=A6=96=E6=AC=A1=E8=A7=A6=E9=9B=B7=E7=B4=AF=E8=AE=A1?= =?UTF-8?q?=E5=B4=A9175=E6=AC=A1=E5=85=A8=E9=A1=B9=E7=9B=AE=E5=81=9C?= =?UTF-8?q?=E6=91=86)=20=E2=91=A1=E8=B5=84=E8=B4=A8=E4=B8=8D=E9=98=BB?= =?UTF-8?q?=E5=A1=9E=E6=A0=87=E4=B9=A6=E6=8E=A8=E8=BF=9B(=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E8=A3=81=E5=AE=9A):CH=5FSECTION=5FDEPS.business?= =?UTF-8?q?=E7=A7=BB=E9=99=A4QUALS=E4=BE=9D=E8=B5=96+=E5=88=A0=E9=99=A4hd?= =?UTF-8?q?=5Fpending/biz=5Fok=E5=95=86=E5=8A=A1=E7=AB=A0=E9=97=A8?= =?UTF-8?q?=E7=A6=81(=E8=B5=84=E8=B4=A8=E7=BC=BA=E5=8F=A3=3D=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=B5=81=E5=BE=85=E5=8A=9E,=E9=9D=9E=E9=97=A8?= =?UTF-8?q?=E7=A6=81=E6=B5=81)+DIM=5FUPSTREAM.cost=5Fbenefit=E5=8E=BB?= =?UTF-8?q?=E6=8E=89quals(=E4=B8=8E=E5=A3=B0=E6=98=8E=E5=B1=82analysis=5Fc?= =?UTF-8?q?ost=5Fbenefit.deps=E5=AF=B9=E9=BD=90,=E6=8A=A5=E4=BB=B7?= =?UTF-8?q?=E9=93=BE=E4=B8=8D=E5=86=8D=E8=A2=AB=E8=B5=84=E8=B4=A8QC?= =?UTF-8?q?=E5=86=BB=E7=BB=93)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pipeline_bidding/bid_flow.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/pipeline_bidding/bid_flow.py b/pipeline_bidding/bid_flow.py index 8b067c4..ef065be 100644 --- a/pipeline_bidding/bid_flow.py +++ b/pipeline_bidding/bid_flow.py @@ -104,7 +104,11 @@ DIM_UPSTREAM = { "scoring": (), "quals": ("scoring",), "reqs_outline": ("scoring",), - "cost_benefit": ("scoring", "quals", "reqs_outline"), + # 2026-09-15 用户裁定:资质有无/资质QC不阻塞标书推进。cost_benefit 测算 + # (保证金/预算/付款条件)实际依据评分项与投标文件要求,不依赖资质清单; + # 且 BID_FLOW_STAGES 声明层 analysis_cost_benefit.deps 本就无 analysis_quals + # ——机制层与声明层对齐(原不一致:quals QC 卡住连报价章全链冻结)。 + "cost_benefit": ("scoring", "reqs_outline"), } # 维度 → 落库表(落库核验用;reqs_outline 维度同时写两张表) @@ -119,10 +123,12 @@ DIM_TABLES = { # 通过 QC——某一维度 QC 卡住只阻塞依赖它的章节,其余章节照常流转。 # 公共事实:章节骨架(bid_chapters)本身就是章节,OUTLINE 过了章节才可信; # REQS(投标文件格式要求)决定章节怎么写,所有章节都要。 +# 2026-09-15 用户裁定:资质有无/QC过否不阻塞标书编写——business 移除 QUALS 依赖 +# (资质缺口走 human_docs_request 待办通知人类,属信息流不是门禁流)。 CH_SECTION_DEPS = { "technical": (QC_TYPE_SCORING, QC_TYPE_REQS, QC_TYPE_OUTLINE), "price": (QC_TYPE_SCORING, QC_TYPE_COST, QC_TYPE_OUTLINE), - "business": (QC_TYPE_QUALS, QC_TYPE_REQS, QC_TYPE_OUTLINE), + "business": (QC_TYPE_REQS, QC_TYPE_OUTLINE), } @@ -999,15 +1005,18 @@ async def reconcile_project(sor, project_id, project_name=""): await sor.sqlExe("COMMIT", {}) if prev: prev_imp = rec_to_dict(prev[0]).get("improvement") or "" + # ⚠ audit_log 表只有 created_at(models/audit_log.json 与库一致), + # 曾写 updated_at → 1054 使整个 reconcile_project 崩溃、全项目派发停摆 + # (2026-09-15 甘肃项目实测:第3轮复审派发路径首次触雷,累计崩 175 次)。 fx = await sor.sqlExe( - "SELECT action, entity, detail, updated_at FROM audit_log " + "SELECT action, entity, detail, created_at FROM audit_log " "WHERE tenant_id=${p}$ AND entity IN ('bid_chapters','bid_doc_requirements'," "'bid_scoring_items','bid_qualifications','bid_cost_benefit') " - "ORDER BY updated_at DESC LIMIT 30", + "ORDER BY created_at DESC LIMIT 30", {"p": project_id}) await sor.sqlExe("COMMIT", {}) fixes = "\n".join( - "- [%s] %s/%s: %s" % (rec_to_dict(f).get("updated_at", "")[:16], + "- [%s] %s/%s: %s" % (rec_to_dict(f).get("created_at", "")[:16], rec_to_dict(f).get("entity", ""), rec_to_dict(f).get("action", ""), (rec_to_dict(f).get("detail") or "")[:80]) @@ -1030,7 +1039,8 @@ async def reconcile_project(sor, project_id, project_name=""): # ── B. 资料准备(知识库资质匹配 + 人类文件清单)── # 2026-09-03 章节级依赖:资料准备是商务章(business)的上游依赖, # 不再阻塞全局流转——技术/报价章在上游 QC 通过后立即开写。 - # 2026-09-11 流程裁剪:prep 被裁 → 不派;商务章 biz_ok 判定同步视为完成。 + # 2026-09-11 流程裁剪:prep 被裁 → 不派。 + # 2026-09-15 起资料准备不再阻塞商务章(资质缺口=信息流,见下方 C 段注释)。 prep_done = (not _stage_on(STAGE_PREP)) or await has_done_task(sor, project_id, R_PREP) if _stage_on(STAGE_PREP) and n_quals > 0 and not prep_done: if await count_open_tasks(sor, project_id, role=R_PREP) > 0: @@ -1054,8 +1064,12 @@ async def reconcile_project(sor, project_id, project_name=""): # 其余章节照常流转(根治:此前五类 QC 全过才放行,cost_benefit 一个维度慢 # 导致全部章节冻结)。商务章额外等资料准备完成。 qc_passed = await _qc_passed_eff() - hd_pending = await find_human_task(sor, project_id, HT_HUMAN_DOCS, status="pending") - biz_ok = (prep_done or n_quals == 0) and not hd_pending + # 2026-09-15 用户裁定:资质文件待办(human_docs_request)不再阻塞任何章节编写。 + # 原 biz_ok=(prep_done or n_quals==0) and not hd_pending 会把「人类没上传资质文件」 + # 变成商务章硬门禁——用户明确说忽略也不管用(答复还会被 agent QC 退回,见 + # human_task_capability 的人类权威规则)。资质缺口是信息流(待办通知),不是门禁流。 + # prep(资料准备)也不再挡商务章:与声明层对齐(chapter_write.deps 只有 + # analysis_reqs_outline),写者需要资质信息时自查知识库/待办清单。 created_w = 0 waiting_deps = {} for c in chapters: @@ -1075,9 +1089,6 @@ async def reconcile_project(sor, project_id, project_name=""): if unmet: waiting_deps.setdefault("/".join(sorted(unmet)), []).append(str(c.get("chapter_no"))) continue - if section == "business" and not biz_ok: - waiting_deps.setdefault("bid_prep(资料准备)", []).append(str(c.get("chapter_no"))) - continue stage = "revise" if c.get("status") == CH_REJECTED else "write" tid = await create_role_task( sor, project_id, role,