1
0
Эх сурвалжийг харах

重做红旗词检测:全文扫描收敛为结构化字段扫描,research/降级WARN

对抗审查(P1-22/23/24/25)实测:旧版全文红旗词扫描对10条合理句子
误杀9条——「诚实边界:xx未实测」是项目自己要求写的内容,写了反被
机器判成造假;「不是自评分」越澄清越被拦。本次重做:

1. 只扫关键字段行(测试日期/总分/各维评分等,须为「字段名+冒号/
   表格分隔符」结构),正文叙述一概不扫——审查报告9条误杀句全部
   通过,「评分日期格式统一为YYYY-MM-DD」这类说明句也免疫
2. 否定语境免疫:命中词前文若是「不是/绝不/NOT a」等否定表达,
   视为主动澄清不算命中
3. 英文词绑定分数上下文(estimated score),不再拦
   "Estimated reading time";删掉裸placeholder/self-assess全文匹配
4. references/research/ 从❌降为⚠️(15个官方examples里5个自己都
   没有:elon-musk/feynman/munger/naval/taleb,硬门槛比官方示范
   还严),文案注明这是CONTRIBUTING期望结构,请人工确认可溯源性
5. 新规则写进CONTRIBUTING.md收录门槛清单,机器拒PR有据可依
6. 顺手修同一行内的截断提示(命中>8项时标「…等N项」,P2-27)

验证:①5个PR#70式坏样本(日期占位/预估分/NN没填/维度待跑/英文
estimated score)全部检出;②审查报告9条误杀句+1条对照句0误杀;
③15个官方FIDELITY.md红旗0命中,5个仅WARN不拦;④模板本体
references/fidelity-scorecard.md 仍如设计意图被检出。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alchain 1 сар өмнө
parent
commit
cde09d82ce

+ 62 - 25
.github/scripts/community_check.py

@@ -6,9 +6,11 @@
 2. 新增行里的GitHub仓库真实存在且公开
 3. 若目标仓库含SKILL.md(人物/主题skill类)→ 额外要求:
    - FIDELITY.md 存在且总分≥70(B级)
-   - FIDELITY.md 不含自评/占位红旗词(预估、待跑、TBD等——分数须为独立双agent实测结果)
+   - FIDELITY.md 关键字段行(测试日期/总分/各维评分)不得为占位或预估
+     (待跑、预估、TBD、YYYY-MM-DD等——分数须为独立双agent实测结果;
+     只扫字段行不扫全文,诚实边界等正文表述不会触发)
    - SKILL.md 含「诚实边界」章节
-   - 有 references/ 目录,且含 references/research/ 调研底稿目录(CONTRIBUTING明文门槛)
+   - 有 references/ 目录;references/research/ 子目录缺失仅记⚠️请人工确认
    若不含SKILL.md(合集/工具类)→ 仅存在性检查,标注请人工确认类别
 4. 结果贴成PR评论
 
@@ -24,37 +26,69 @@ import urllib.request
 
 API = "https://api.github.com"
 
-# FIDELITY.md 自评/占位红旗词:命中即判❌。
+# FIDELITY.md 占位/预估检测:结构化字段扫描,命中即判❌。
 # 依据:保真度分数必须来自独立双agent实测(见 references/fidelity-scorecard.md),
 # 「预填模板+补一行总分」不算跑过测试(先例:PR #70)。
-# 注意:不收录裸「自评」——官方模板引用SkillLens论文时含「LLM自评准确率」字样,会误伤。
-FIDELITY_RED_FLAGS = [
-    "预估",       # 「预估分」「预估总分」
-    "待跑", "待测", "待补", "待定",
-    "占位",
-    "未实测", "未测试",
-    "自评分",     # 「自评分数」,区别于论文引用里的「自评准确率」
-    "YYYY-MM-DD",  # 模板日期没填
-]
-FIDELITY_RED_FLAG_PATTERNS = [
+# 设计约束(2026-07-26对抗审查 P1-22/P1-23):
+# 1. 只扫「关键字段行」(测试日期/总分/各维评分等),绝不全文搜词——
+#    「诚实边界:xx未实测」是项目自己要求写的内容,不能被判成造假;
+# 2. 否定语境免疫:「不是自评分」「NOT a self-assessment」不算命中;
+# 3. 英文词绑定分数上下文(estimated score),不拦 "Estimated reading time"。
+# 宁可漏判交给人工,也不让守规矩的投稿被机器误拒。
+
+# 关键字段行:行首(允许 >、#、*、-、| 等markdown前缀)出现「字段名 + 冒号/表格分隔符」。
+# 「评分日期格式统一为YYYY-MM-DD」这类叙述句因字段名后无分隔符,不会被当成字段行。
+FIDELITY_KEY_FIELD_RE = re.compile(
+    r"^[\s>#*\-|]*(?:测试日期|评分日期|测试时间|测试模型|总分|综合得分|最终得分|得分|评分"
+    r"|维度\s*\d+|立场一致性|风格辨识度|边缘诚实度|来源透明度|结构完整度"
+    r"|total(?:\s+score)?|overall(?:\s+score)?|final\s+score|test\s+date|score|date)"
+    r"[\s*]*[::|]",
+    re.IGNORECASE,
+)
+# 占位/预估标记(仅在关键字段行内查找)
+FIDELITY_PLACEHOLDER_PATTERNS = [
+    (r"预估", "预估"),
+    (r"待跑", "待跑"),
+    (r"待测", "待测"),
+    (r"待补", "待补"),
+    (r"待定", "待定"),
+    (r"待填", "待填"),
+    (r"占位", "占位"),
+    (r"未实测", "未实测"),
+    (r"未测试", "未测试"),
+    (r"自评分", "自评分"),   # 区别于论文引用里的「自评准确率」,裸「自评」不收
+    (r"YYYY[-/年]?\s*MM", "YYYY-MM-DD(模板日期没填)"),
     (r"\bTBD\b", "TBD"),
     (r"\bTODO\b", "TODO"),
     (r"self[- ]assess\w*", "self-assessed"),
-    (r"\bestimated?\b", "estimated"),
+    (r"\bestimated\s+(?:score|total|rating|grade)", "estimated score"),
     (r"\bplaceholder\b", "placeholder"),
     (r"\bNN\s*/\s*\d+", "NN/100(模板分数没填)"),
 ]
+# 否定语境:命中词紧邻的前文若是否定表达,视为主动澄清而非占位
+FIDELITY_NEGATION_RE = re.compile(
+    r"(?:不是|并非|绝不|从不|不算|不做|没有|不存在|未使用|无"
+    r"|not(?:\s+an?)?|isn'?t(?:\s+an?)?|never|no)[\s*'\"「」((]*$",
+    re.IGNORECASE,
+)
 
 
 def find_fidelity_red_flags(text):
-    """扫描FIDELITY.md全文,返回命中的红旗词列表(去重、保持顺序)。"""
+    """结构化字段扫描FIDELITY.md:只检查关键字段行是否为占位/预估。
+
+    返回命中标记列表(去重、保持顺序)。非字段行(诚实边界、局限说明等正文)不扫描。
+    """
     hits = []
-    for w in FIDELITY_RED_FLAGS:
-        if w in text:
-            hits.append(w)
-    for pat, label in FIDELITY_RED_FLAG_PATTERNS:
-        if re.search(pat, text, re.IGNORECASE):
-            hits.append(label)
+    for line in text.splitlines():
+        if not FIDELITY_KEY_FIELD_RE.match(line):
+            continue
+        for pat, label in FIDELITY_PLACEHOLDER_PATTERNS:
+            for m in re.finditer(pat, line, re.IGNORECASE):
+                prefix = line[max(0, m.start() - 16):m.start()]
+                if FIDELITY_NEGATION_RE.search(prefix):
+                    continue  # 否定语境(「不是自评分」「NOT a self-assessment」)
+                hits.append(label)
+                break
     return list(dict.fromkeys(hits))
 
 
@@ -98,7 +132,8 @@ def check_target_repo(slug, token):
         if isinstance(research, list) and research:
             items.append(("✅", "含 references/research/ 调研底稿目录"))
         else:
-            items.append(("❌", "缺 references/research/ 调研底稿目录(CONTRIBUTING收录门槛:用女娲流程蒸馏,自包含可溯源)"))
+            items.append(("⚠️", "未见 references/research/ 子目录(CONTRIBUTING期望的调研底稿结构)。"
+                                "若调研底稿直接放在 references/ 下,请维护者人工确认可溯源性即可,不作硬性拦截"))
     else:
         items.append(("❌", "缺 references/ 调研底稿(skill需自包含可溯源)"))
 
@@ -115,11 +150,13 @@ def check_target_repo(slug, token):
             items.append(("❌", f"保真度 {m.group(1)}/100 未达B级门槛(70)"))
         red_flags = find_fidelity_red_flags(fidelity)
         if red_flags:
-            items.append(("❌", "FIDELITY.md 检出自评/占位字样:`" + "`、`".join(red_flags[:8])
-                          + "`。保真度分数须由独立双agent实测产生(方法见 references/fidelity-scorecard.md),"
+            items.append(("❌", "FIDELITY.md 关键字段(测试日期/总分/评分)检出占位或预估:`"
+                          + "`、`".join(red_flags[:8])
+                          + ("`" if len(red_flags) <= 8 else f"`…等{len(red_flags)}项")
+                          + "。保真度分数须由独立双agent实测产生(方法见 references/fidelity-scorecard.md),"
                             "预填模板或自评预估分不满足收录门槛,请实测后更新评分卡"))
         else:
-            items.append(("✅", "FIDELITY.md 未检出自评/占位字样"))
+            items.append(("✅", "FIDELITY.md 关键字段未检出占位/预估"))
 
     ok = all(mark != "❌" for mark, _ in items)
     return ok, items

+ 1 - 0
CONTRIBUTING.md

@@ -23,6 +23,7 @@
 - 用女娲流程蒸馏,仓库内含 `references/research/` 调研底稿(自包含,可溯源)
 - 有「诚实边界」和「反模式」章节
 - 保真度评分卡 ≥ B(70分),仓库根目录放 `FIDELITY.md`
+- `FIDELITY.md` 的关键字段(测试日期/总分/各维评分)须为独立双agent实测的真实值,不得是「待跑」「预估」「TBD」「YYYY-MM-DD」等占位或预估——机器检查按此拦截
 - 通过伦理红线检查(见下)
 
 提交收录PR后,机器人会自动检查以上形式门槛并把✅/❌清单贴成评论(改完推送会自动重跑);机器检查通过后,维护者人工确认伦理红线和内容质量即可合并。