zizi cf0f4fb985 W20–W24:保存知识方法、迁移框架、审校修订与案例行为的集成成果
接续 88dd570,保存 W20–W24 已实现的共享接口、业务入口、迁移、工作台、测试与文档。
W20/W22/W23 保持 in_progress,W21/W24 保持 verified;此提交不宣称方法或规则正式启用、多轮返修、真实角色评测完成。

W25 新增实验、标定、逐调用交付与角色执行及其迁移/测试/索引留在实施工作树,原有私人和旧实现保留项不纳入。

验证:离线 571、前端 33 通过;PG 469 项通过、2 项浏览器未启用,2 项误带入的 W25 用例已移出本提交;最终任务与交付边界 37 项通过。make 检查、最终类型、84 项资源及 diff 检查通过。未重跑浏览器或 Pi 宿主,不以合成调用认证外部模型效果。
独立整体审查四维通过;证据保存在 R2-20260909/提交W20-W24。
2026-09-13 16:24:42 +08:00

90 lines
3.8 KiB
Python

"""固定旧结构上的字段归一与校验;未知值进入隔离,不调用模型或联网取定义。"""
from __future__ import annotations
from typing import Any
from jsonschema import Draft202012Validator
from jsonschema.exceptions import SchemaError
from referencing.exceptions import Unresolvable
from 建立映射 import 稳定JSON, 迁移错误
def 取一致值(值: dict, 键: tuple[str, ...], *, 默认: Any = None, 原因: str = "field_conflict"):
已有 = [值[k] for k in 键 if k in 值]
if not 已有:
return 默认
if any(稳定JSON(v) != 稳定JSON(已有[0]) for v in 已有[1:]):
raise 迁移错误(原因, "冲突键:" + "/".join(键))
return 已有[0]
def 转换动态字段(字段: Any, type_id: str, schemas: dict) -> dict:
if not isinstance(字段, dict):
raise 迁移错误("field_type_mismatch", "动态字段必须是对象")
合同 = schemas.get(type_id)
if (
not isinstance(合同, dict)
or 合同.get("type") != "object"
or 合同.get("additionalProperties") is not False
):
raise 迁移错误("schema_mapping_missing", "需要明确拒绝未知字段的固定结构")
def 检查引用(值):
if isinstance(值, dict):
for k, v in 值.items():
if k in {"$ref", "$dynamicRef"} and (
not isinstance(v, str) or not v.startswith("#")
):
raise 迁移错误("schema_invalid", "迁移不能联网获取结构定义")
检查引用(v)
elif isinstance(值, list):
for v in 值:
检查引用(v)
检查引用(合同)
try:
Draft202012Validator.check_schema(合同)
错误 = next(iter(Draft202012Validator(合同).iter_errors(字段)), None)
except (SchemaError, RecursionError, Unresolvable) as 错:
raise 迁移错误("schema_invalid", "固定结构无法解释") from 错
if 错误 is not None:
代码 = {
"additionalProperties": "unknown_fields",
"required": "missing_required",
"type": "field_type_mismatch",
}.get(错误.validator, "field_invalid")
raise 迁移错误(代码, "动态字段不符合固定结构:" + "/".join(map(str, 错误.path)))
return 字段
def 转换目标字段(内容: dict, 字段映射: Any) -> dict:
"""只做显式的一层字段映射;不执行表达式,不补默认值,不漏掉动态字段。"""
if not isinstance(字段映射, dict) or not 字段映射:
raise 迁移错误("target_schema_missing", "目标字段映射必须明确给出")
字段 = 内容.get("fields", {})
结果, 已用 = {}, set()
端点字段 = {
"source": {"甲方", "甲方draft", "甲方名称"},
"target": {"乙方", "乙方draft", "乙方名称"},
"relation_type": {"关系类型"},
}
for 目标, 源 in 字段映射.items():
if not isinstance(目标, str) or not 目标 or not isinstance(源, str):
raise 迁移错误("target_field_invalid", "字段映射需要明确的字段名和来源")
if 源.startswith("fields."):
名 = 源.removeprefix("fields.")
if 名 not in 字段:
raise 迁移错误("target_field_missing", "原行缺少被选择的动态字段")
结果[目标] = 字段[名]
已用.add(名)
elif 源 in {"name", "brief", "source", "target", "relation_type"} and 源 in 内容:
结果[目标] = 内容[源]
已用.update(端点字段.get(源, set()))
else:
raise 迁移错误("target_field_invalid", "字段来源不是已归一值或一级动态字段")
if set(字段) - 已用:
raise 迁移错误("target_field_unmapped", "有动态字段未映射,不能静默丢弃")
return 结果