From b1493519605a08ca867d5f0c31e506410f44fbb2 Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Wed, 14 Oct 2026 16:11:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5=E7=9B=AE=E5=BD=95=EF=BC=9A?= =?UTF-8?q?=E6=8E=A8=E6=96=AD=E3=80=81=E6=9C=89=E7=A1=AE=E8=AF=81=E7=9A=84?= =?UTF-8?q?=E9=A1=B9=E5=9C=A8=E6=A0=A1=E9=AA=8C=E4=B9=8B=E5=89=8D=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E7=A1=AE=E8=AE=A4=E6=97=B6=E7=9A=84=E4=BE=9D=E6=8D=AE?= =?UTF-8?q?=EF=BC=8C=E6=89=8B=E6=94=B9=E8=BF=87=E7=9A=84=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E9=87=8C=E4=BE=9D=E6=8D=AE=E4=B8=8D=E5=90=88=E8=A7=84=E4=B9=9F?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E6=8A=8A=E6=95=B4=E9=A1=B9=E8=B7=B3=E8=BF=87?= =?UTF-8?q?=EF=BC=88=E7=85=A7=E5=B8=B8=E5=8F=AA=E5=A1=AB=E7=A9=BA=E7=BC=BA?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E5=B7=B2=E7=A1=AE=E8=AE=A4=E3=80=81=E5=B7=B2?= =?UTF-8?q?=E9=A9=B3=E5=9B=9E=E7=9A=84=E9=A1=B9=E4=BE=9D=E6=8D=AE=E4=B8=8D?= =?UTF-8?q?=E5=90=88=E8=A7=84=E7=85=A7=E6=97=A7=E8=B7=B3=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/data/catalog_transfer.py | 5 +++-- backend/tests/test_catalog_transfer.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/backend/app/data/catalog_transfer.py b/backend/app/data/catalog_transfer.py index b0badbdf..39bab51d 100644 --- a/backend/app/data/catalog_transfer.py +++ b/backend/app/data/catalog_transfer.py @@ -396,6 +396,9 @@ def plan_table(table_name: str, target: str, file_notes: Mapping[str, Any], targ if why is not None: plan.skipped.append({"path": path, "why": why}) continue + if isinstance(item, dict) and item.get("status") not in _LOCKED and "reason" in item: + # 推断、有确证的项不带确认时的依据:在校验之前去掉,手改的文件里依据不合规也不把整项跳过 + item = {k: v for k, v in item.items() if k != "reason"} problem = _item_problem(mapped or key, item) if problem is not None or mapped is None: plan.skipped.append({"path": path, "why": problem or "无法识别这一项"}) @@ -405,8 +408,6 @@ def plan_table(table_name: str, target: str, file_notes: Mapping[str, Any], targ continue seen.add(mapped) status = item.get("status") - if status not in _LOCKED: - item = {k: v for k, v in item.items() if k != "reason"} # 推断、有确证的项不带确认时的依据 have = existing.get(mapped) if have is None: plan.add += 1 diff --git a/backend/tests/test_catalog_transfer.py b/backend/tests/test_catalog_transfer.py index ba861de3..61a210cb 100644 --- a/backend/tests/test_catalog_transfer.py +++ b/backend/tests/test_catalog_transfer.py @@ -411,3 +411,22 @@ async def test_round_trip_into_an_empty_copy_reproduces_the_catalog(client): expected["relations"] = [r for r in mine.notes["relations"] if r["to_table"] != "stores"] del expected["columns"]["gift_flag"] # 表结构里没有这一列 assert theirs.notes == expected + + +async def test_a_bad_reason_on_an_inferred_item_is_dropped_not_the_item(client): + """手改过的文件里,推断的项带着不合规的确认时的依据(推断项本来就不该有依据):去掉依据、照常填空缺,不把整项跳过。 + 已确认的项依据不合规照旧跳过(依据是它的一部分,照带就得合规)。""" + local, remote = await _pair() + content = await _export(client, local) + notes = content["tables"]["orders"]["notes"] + notes["grain"] = {"value": "每笔订单一行", "source": "llm", "status": "proposed", "reason": "依" * 600} + notes["description"] = {"value": "订单头", "source": "human", "status": "confirmed", "reason": 42} + report = (await client.post(f"{_base(remote)}/import/preview", json={"content": content})).json() + skipped = {s["path"]: s["why"] for s in _by(report)["ORDERS"]["skipped"]} + assert "grain" not in skipped + assert "description" in skipped and "依据" in skipped["description"] + r = await client.post(f"{_base(remote)}/import", json={"content": content}) + assert r.status_code == 200, r.text + assert "grain" not in {s["path"] for s in _by(r.json())["ORDERS"]["skipped"]} + got = (await client.get(f"{_base(remote)}/ORDERS")).json()["notes"] + assert "reason" not in got["grain"] # 目标原有的推断粒度保留(推断只填空缺),也没被挂上依据