From 19bdcf55d87f0cfd241ce7d86a62e919fa1900f7 Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Wed, 21 Oct 2026 16:11:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E6=9E=90=E5=8D=A1=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E5=AF=B9=E5=90=88=E5=B9=B6=E5=90=8E=E7=9A=84=E9=98=88?= =?UTF-8?q?=E5=80=BC=E5=86=8D=E6=A0=B8=E4=B8=80=E9=81=8D=EF=BC=88=E5=A4=8D?= =?UTF-8?q?=E6=A0=B8=20R28=EF=BC=89=EF=BC=9A=E7=94=BB=E5=9B=BE=E6=97=B6?= =?UTF-8?q?=E9=98=88=E5=80=BC=E8=A6=86=E7=9B=96=E5=8F=AA=E8=83=BD=E5=AF=B9?= =?UTF-8?q?=E7=9D=80=E7=BC=BA=E7=9C=81=E5=80=BC=E6=A0=A1=E9=AA=8C=EF=BC=88?= =?UTF-8?q?schema=20=E4=B8=8D=E6=94=B9=EF=BC=89=EF=BC=8C=E5=8F=91=E8=B5=B7?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E8=AE=BE=E7=BD=AE=E5=BF=AB=E7=85=A7=E5=90=88?= =?UTF-8?q?=E8=BF=9B=E6=9D=A5=E4=BB=A5=E5=90=8E=E5=8F=AF=E8=83=BD=E5=86=B2?= =?UTF-8?q?=E7=AA=81=E2=80=94=E2=80=94=E7=AE=A1=E7=90=86=E5=91=98=E6=8A=8A?= =?UTF-8?q?=E3=80=8C=E8=B6=85=E5=87=BA=E5=B8=B8=E8=A7=84=E6=B3=A2=E5=8A=A8?= =?UTF-8?q?=E3=80=8D=E8=B0=83=E5=88=B0=203=E3=80=81=E5=8D=A1=E4=B8=8A?= =?UTF-8?q?=E6=8A=8A=E3=80=8C=E6=98=8E=E6=98=BE=E8=B6=85=E5=87=BA=E3=80=8D?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E6=88=90=202.5=EF=BC=8C=E5=B0=B1=E6=B0=B8?= =?UTF-8?q?=E8=BF=9C=E5=88=A4=E4=B8=8D=E5=87=BA=E8=B6=85=E5=87=BA=E3=80=82?= =?UTF-8?q?=E5=8D=A1=E4=B8=8A=E5=86=99=E4=BA=86=E8=A6=86=E7=9B=96=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AF=B9=E7=BC=BA=E7=9C=81?= =?UTF-8?q?=20=E2=86=90=20=E5=BF=AB=E7=85=A7=20=E2=86=90=20=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E5=90=88=E5=B9=B6=E5=90=8E=E7=9A=84=E9=98=88=E5=80=BC?= =?UTF-8?q?=E8=B7=91=E4=B8=80=E6=AC=A1=20contract.settings=5Fproblem?= =?UTF-8?q?=EF=BC=8C=E6=9C=89=E9=97=AE=E9=A2=98=E8=AE=A9=E5=8D=A1=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E5=B9=B6=E8=AF=B4=E6=B8=85=E3=80=8C=E9=98=88=E5=80=BC?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E5=92=8C=E8=BF=99=E6=AC=A1=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E7=9A=84=E5=88=86=E6=9E=90=E8=AE=BE=E7=BD=AE=E5=86=B2=E7=AA=81?= =?UTF-8?q?=EF=BC=9A=E2=80=A6=E3=80=82=E8=AF=B7=E6=94=B9=E5=88=86=E6=9E=90?= =?UTF-8?q?=E5=8D=A1=E4=B8=8A=E7=9A=84=E9=98=88=E5=80=BC=E8=A6=86=E7=9B=96?= =?UTF-8?q?=E3=80=8D=EF=BC=88=E9=85=8D=E7=BD=AE=E9=94=99=E8=AF=AF=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E6=98=AF=E6=95=B0=E6=8D=AE=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E4=B8=80=E9=A1=B9=E9=83=BD=E4=B8=8D=E7=AE=97=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/engine/nodes/analysis.py | 7 ++++++- backend/tests/test_analysis_card_data.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/backend/app/engine/nodes/analysis.py b/backend/app/engine/nodes/analysis.py index 80501458..3c622232 100644 --- a/backend/app/engine/nodes/analysis.py +++ b/backend/app/engine/nodes/analysis.py @@ -56,7 +56,12 @@ async def run_analysis(state: GraphState, ctx: NodeContext) -> dict[str, Any]: if errors := [i for i in analysis_issues(ctx.run.spec, ctx.node) if i.level == "error"]: raise NodeError(ctx.node.id, errors[0].message) items: list[dict[str, Any]] = ctx.config["items"] - settings = await settings_of(run_snapshot(ctx.run), ctx.config.get("overrides") or None) + overrides = ctx.config.get("overrides") or None + settings = await settings_of(run_snapshot(ctx.run), overrides) + # 画图时阈值覆盖只能对着缺省值校验;合并了这次运行的设置快照以后再核一遍(管理员把「超出常规波动」调到 3、卡上把「明显 + # 超出」覆盖成 2.5,就永远判不出超出)。这是配置错误,不是数据问题:让卡失败、说清冲突在哪 + if overrides and (problem := contract.settings_problem(settings)): + raise NodeError(ctx.node.id, f"阈值覆盖和这次运行的分析设置冲突:{problem}。请改分析卡上的阈值覆盖") queries = [e for e in state.get("evidence") or [] if isinstance(e, dict) and e.get("kind") == "query"] inputs: dict[str, InputSnapshot] = {} diff --git a/backend/tests/test_analysis_card_data.py b/backend/tests/test_analysis_card_data.py index 755df707..179ef740 100644 --- a/backend/tests/test_analysis_card_data.py +++ b/backend/tests/test_analysis_card_data.py @@ -68,3 +68,16 @@ async def test_a_structural_call_error_still_fails_the_card_and_names_the_item() assert row.status == "failed" assert "分析项「where」(变化拆解)" in row.error and "没有「channel」这一列" in row.error assert "请在分析卡中改正这一项" in row.error + + +async def test_overrides_that_conflict_with_the_run_settings_fail_the_card(): + # 画图时对着缺省值校验能过(缺省「超出常规波动」是 2);这次运行的设置把它调到 3,卡上覆盖的「明显超出」2.5 就永远判不出 + card = node("card", "analysis", items=[WHERE], overrides={"k_alert": 2.5}) + graph = chain(node("start", "input"), node("by_region", "tool", tool=TOOL, args={"sql": BY_REGION}), card) + run = await run_manager.start(graph=graph, input_payload={}, options={"analysis": {"k_warn": 3.0}}) + row = await wait(run.id) + assert row.status == "failed" + assert "阈值覆盖和这次运行的分析设置冲突:「明显超出」的倍数要大于「超出常规波动」的倍数" in row.error + assert await events(row.id, "analysis.end", "card") == [] + ok = await run_manager.start(graph=graph, input_payload={}, options={"analysis": {"k_warn": 2.0}}) + assert (await wait(ok.id)).status == "succeeded"