fix: 词表墙的四项审查修复(es 池降级/占位符白名单校验/键 allowlist/提取自检+防呆测试)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -20,11 +20,18 @@ import html as html_mod
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
from bisect import bisect_right
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from tokenize import COMMENT, generate_tokens
|
||||
|
||||
# 本仓库引擎编译器(仅 stdlib 依赖,无源项目 import 链,import 安全——
|
||||
# "绝不 import 源模块"约束针对的是老项目 app.*,非本文件所在仓库)。
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
from app.engine.wall_schema import (TEMPLATE_PLACEHOLDERS, WallConfigError,
|
||||
compile_wall)
|
||||
|
||||
# ---- 占位符映射(函数体内联话术的插值表达式 → wall 模板占位符) ----
|
||||
# 源码里的 f"{shown}" / 拼接 NO_CONTACT_WEB 等,在 wall.json 里以
|
||||
# {shown} / {no_contact_web} 占位,运行期由 conversation.py .format() 回填。
|
||||
@@ -37,6 +44,16 @@ PLACEHOLDER_NAMES = {
|
||||
}
|
||||
PLACEHOLDER_CALLS = {"_cc_script": "cc_script"}
|
||||
|
||||
# 单一来源反查(审查 I-2): 引擎侧白名单 wall_schema.TEMPLATE_PLACEHOLDERS
|
||||
# 是唯一权威,本脚本产出的占位符必须 ⊆ 白名单——清单漂移(此处新增映射
|
||||
# 而引擎未同步)在提取期立即显性失败,而非运行期 .format() KeyError。
|
||||
if not (set(PLACEHOLDER_NAMES.values()) | set(PLACEHOLDER_CALLS.values())
|
||||
<= TEMPLATE_PLACEHOLDERS):
|
||||
raise SystemExit(
|
||||
"提取失败: 占位符超出 wall_schema.TEMPLATE_PLACEHOLDERS 白名单: "
|
||||
+ ", ".join(sorted((set(PLACEHOLDER_NAMES.values())
|
||||
| set(PLACEHOLDER_CALLS.values())) - TEMPLATE_PLACEHOLDERS)))
|
||||
|
||||
|
||||
class NotExtractable(Exception):
|
||||
"""表达式超出受限求值语法(非目标常量,跳过)。"""
|
||||
@@ -220,6 +237,9 @@ def attach_price_comments(src: str, assign: ast.Assign,
|
||||
"""PRICE_PATTERNS 列表内的 # 注释块挂到紧随其后的条目(comment 键)。
|
||||
|
||||
防误杀断言的设计说明随 pattern 一并数据化,编辑 wall.json 的人能看见。
|
||||
边界注释有意丢弃(审查 M-2 备案): 首条目之前/末条目之后的注释没有
|
||||
可挂靠的条目(bisect 落在 0/len(entries) 之外)——首条目前的通常是
|
||||
分组标题注释,本就不属于任何单条 pattern 的设计说明,丢弃不损信息。
|
||||
"""
|
||||
comments: list[tuple[int, str]] = []
|
||||
for tok in generate_tokens(StringIO(src).readline):
|
||||
@@ -272,9 +292,12 @@ def build_wall(project_root: Path, slug: str) -> dict:
|
||||
return table[name]
|
||||
|
||||
# price_patterns: 统一先建 dict 以便挂行内注释,无 flags 且无 comment 再瘦回字符串
|
||||
price_assign = next(n for n in bf_tree.body
|
||||
if isinstance(n, ast.Assign)
|
||||
and getattr(n.targets[0], "id", "") == "PRICE_PATTERNS")
|
||||
price_assign = next((n for n in bf_tree.body
|
||||
if isinstance(n, ast.Assign)
|
||||
and getattr(n.targets[0], "id", "") == "PRICE_PATTERNS"),
|
||||
None)
|
||||
if price_assign is None: # 防呆(审查 M-1): 源码重构挪走赋值节点时显性失败
|
||||
raise SystemExit(f"提取失败: {slug} 源码缺 PRICE_PATTERNS 赋值节点")
|
||||
price_entries: list[dict] = []
|
||||
for r in need(bf, "PRICE_PATTERNS"):
|
||||
e: dict = {"pattern": r["pattern"]}
|
||||
@@ -475,6 +498,16 @@ def write_json(path: Path, data: dict) -> None:
|
||||
encoding="utf-8", newline="\n")
|
||||
|
||||
|
||||
def _self_check(wall: dict, slug: str) -> None:
|
||||
"""提取自检(审查 I-4): 落盘前跑 compile_wall,把"提取静默漏项"
|
||||
(锚点漂移/结构缺失/坏 regex/非法占位符)收敛到提取期失败——带 slug
|
||||
上下文显性报错,而非留到引擎加载或客户会话运行期才炸。"""
|
||||
try:
|
||||
compile_wall(wall)
|
||||
except WallConfigError as exc:
|
||||
raise SystemExit(f"提取自检失败({slug}): {exc}") from exc
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--jc", default=r"D:\refactor\ai-kefu-jc",
|
||||
@@ -492,6 +525,7 @@ def main() -> None:
|
||||
|
||||
# jiancai(主线,完整提取;多语言墙 = 引擎出厂默认)
|
||||
jc_wall = build_wall(jc_root, "jiancai")
|
||||
_self_check(jc_wall, "jiancai")
|
||||
jc_dir = out_root / "seed_profiles" / "jiancai"
|
||||
write_json(jc_dir / "wall.json", jc_wall)
|
||||
write_json(jc_dir / "brand_values.json", build_brand_values(jc_root))
|
||||
@@ -510,6 +544,7 @@ def main() -> None:
|
||||
"fallback_from": "jiancai",
|
||||
"fields": FALLBACK_FIELDS,
|
||||
}
|
||||
_self_check(auto_wall, "auto")
|
||||
auto_dir = out_root / "seed_profiles" / "auto"
|
||||
write_json(auto_dir / "wall.json", auto_wall)
|
||||
write_json(auto_dir / "brand_values.json", build_brand_values(auto_root))
|
||||
|
||||
Reference in New Issue
Block a user