dsh-fact-check 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ADAPTING.md +2 -2
- package/CHANGELOG.md +35 -0
- package/FOR-AI.md +3 -3
- package/INSTRUCTIONS.md +84 -1
- package/MEASUREMENTS.md +3 -2
- package/README.md +6 -3
- package/README.zh-CN.md +6 -3
- package/SKILL.md +85 -2
- package/cases/README.md +1 -1
- package/cases/route-cases-neutral.json +32 -4
- package/package.json +1 -1
- package/tools/route.mjs +38 -9
- package/tools/source-matrix.json +7 -0
package/ADAPTING.md
CHANGED
|
@@ -22,8 +22,8 @@ node tools/doctor.mjs --write # 生成 local.json 草稿,再
|
|
|
22
22
|
|
|
23
23
|
# 4) 验收(离线,不花钱)
|
|
24
24
|
node tools/jev-verdict.mjs selftest # 期望 25/25
|
|
25
|
-
node tools/route.mjs selftest # 期望
|
|
26
|
-
node tools/route.mjs regress --file cases/route-cases-neutral.json # 期望
|
|
25
|
+
node tools/route.mjs selftest # 期望 44/44
|
|
26
|
+
node tools/route.mjs regress --file cases/route-cases-neutral.json # 期望 30/30
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
要求:**Node 18+**(内置 `fetch` 与 `AbortSignal.timeout`)。零 npm 依赖。
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,41 @@
|
|
|
3
3
|
面向使用者的**版本间净变化**(修复 / 改进 / 新增)。只写最终结果,不写过程。
|
|
4
4
|
判据、阈值、触发词的任何改动都必须同时更新 `MEASUREMENTS.md` 的数字与 `cases/` 的回归结果。
|
|
5
5
|
|
|
6
|
+
## 1.5.1 — 2026-10-28
|
|
7
|
+
|
|
8
|
+
**修复**
|
|
9
|
+
|
|
10
|
+
- **未识别任务的兜底域选错(会劝退该派的活)**:任务文本匹配不到任何触发词时,原先兜底到 `tech_release`——给的是「官方仓库 README/CHANGELOG → 文档站 → 包管理器元数据」这套软件发布阶梯,而且该域 `closed=false`,`dispatchHint` 会说「单路可覆盖,串行处理即可」。对「某平台上两国网民骂战的来龙去脉」这类任务,等于同时给了错误的来源阶梯与错误的派发建议。现改为专用兜底域 `general_fact`:阶梯是「当事方原始发布 → 通讯社与官方广播 → 元搜索交叉 → 存档快照 → 当地媒体 → 社区线索」,`plan` 输出新增 `fallback` 字段,兜底时提示改为「未识别事实类型(兜底域)→ 按 SKILL.md 的信号表判断」。同时补齐两条触发词(`cn_social_rumor` 加 `推特 / Twitter / X 平台 / 骂战 / 对线 / 论战 / 口水战 / 开撕 / 网络战`,`international` 加常见外方国名),让同一类任务不再落兜底。
|
|
11
|
+
- **子代理回报可能被内容审核整条丢弃**:极端题材(族群冲突 / 辱骂 / 暴力)里,子代理逐字复述辱称或族群贬损文本,会让**整条回报**被审核丢弃,那一路渠道的证据就全没了。`SKILL.md`「子代理分发模式(可选)」新增「回报的引文净化」:事实性表述(时间 / 账号名 / tweet_id / 互动量 / 可观察行为特征)照常逐字引;贬损原文改为**中性性质标签 + 原帖 URL + tweet_id + 发布时间**,需要逐字文本时由主对话自己调 syndication / oembed。派发 prompt 必须带上这条约定;回报第一行写 `渠道状态:已取证 / 无命中 / 抓取失败`,把「确实没证据」和「回报丢了」分开。
|
|
12
|
+
|
|
13
|
+
**其它**
|
|
14
|
+
|
|
15
|
+
- `cases/route-cases-neutral.json`:R10 改判 `general_fact` 并反向断言不是 `tech_release`;新增 R27–R30(未识别任务 / X 平台骂战 / 推特对线 / 外方国名进国际域);`regress` 支持 `expectFallback`。
|
|
16
|
+
- `SKILL.md` frontmatter 与 `package.json` 版本号同步到 **1.5.1**;`INSTRUCTIONS.md` 由 `make-instructions.mjs` 重新生成。
|
|
17
|
+
- `MEASUREMENTS.md`:`route` 离线断言 37 → **44 项**、路由语料 26 → **30 例**;§7 增第 10 条记录兜底域修正与两条扩词,并注明 `arms` 的 28/35 与 7 条 mismatch **逐条不变**——新增词条在 35 条共识样本上没改变任何一条判定,样本小,这只说明「未变差」。
|
|
18
|
+
- `ADAPTING.md` / `FOR-AI.md` / `README.md` / `README.zh-CN.md` / `cases/README.md` 里「期望 37/37、26/26」「当前状态」这类**现在时**数字同步到 44/44、30/30;带日期的历史证据行(「某日在该宿主上跑过 37/37」)保持原样,不改写历史。
|
|
19
|
+
- 验收:`selftest 44/44`(原 37)、`regress 30/30`(原 26)、`arms 28/35 = 80.0%` 与 7 条 mismatch **逐条不变**;`jev-verdict selftest 25/25`、`smoke-plugin 27/27` 未受影响。
|
|
20
|
+
- **判据层未动**:`jev-verdict.mjs`、`engine-routes.json`、`lib/` 本轮无改动。
|
|
21
|
+
|
|
22
|
+
## 1.5.0 — 2026-10-23
|
|
23
|
+
|
|
24
|
+
**新增**
|
|
25
|
+
|
|
26
|
+
- **「利益相关与污染面」一节:标注制、不降权、双轨呈现。** 此前来源分级表只有一条轴(来源类型),并把"一手"隐含当成"可信"——真实缺口在于 **provenance(这条说法的源头在哪)** 与 **incentive(说它的人会不会因为"它为真"而获益)** 是两个不同问题,而原表只问了前者。新节**不判定**来源是否存在利益关联、是否被投毒,只做三件事:① 按 **L1 客观可查 / L2 可推断 / L3 不可判定** 三层标注;② 把同一来源的两个角色拆开——**角色 A「它确实说过」**(事实级,不受关联影响,发布行为可单独判已证实)与**角色 B「所以说的是真的」**(受关联与污染影响的那一半);③ 给出**甲轨(标注不参与定档,正式结论)** 与**乙轨(剔除标注源后重算)** 两套固定口径的档位,差额交给读者裁定。
|
|
27
|
+
- **报告模板新增「利益相关与污染面」一节**,并在「一句话结论」里加一行乙轨档位;标注表为空时只写一行"两轨一致",成本随证据量伸缩。
|
|
28
|
+
- **污染面只声明攻击面,不承诺识别投毒**:给出首发时序 / 引用链形状 / 跨生态痕迹 / 结论冗余度四项结构性检查,并明写它们都**不构成"被投毒"的判定**;同时明确承认"一手源本身被投毒"这一类不可解,要求如实写"查不出"而不是假装能查。
|
|
29
|
+
|
|
30
|
+
**为什么不写成降权(三条理由已写进正文)**
|
|
31
|
+
|
|
32
|
+
- **非单调**:任何"没有替代源就不降权"式的条件降权,会让新增一条独立佐证反而触发降权。要做到单调就等价于降权无效,二者不可兼得。
|
|
33
|
+
- **奖励信息垄断**:若"唯一来源"能拿全权重,则"确保别人无法核实"成为拿到高置信度的最优策略——正是投毒与宣传想要的性质。
|
|
34
|
+
- **全局降档**:投毒永远无法排除,把它接进降档条件等价于给全技能统一减一档,判定力归零。
|
|
35
|
+
|
|
36
|
+
**其它**
|
|
37
|
+
|
|
38
|
+
- `SKILL.md` frontmatter 与 `package.json` 版本号同步到 **1.5.0**;`INSTRUCTIONS.md` 由 `make-instructions.mjs` 重新生成。
|
|
39
|
+
- **判定逻辑未变**:档位仍只由「独立源头数」决定;`tools/` 下三个工具与 `cases/` 回归语料本轮**未改动**,`selftest` / `regress` 数字应与 1.4.0 一致。
|
|
40
|
+
|
|
6
41
|
## 1.4.0 — 2026-10-17
|
|
7
42
|
|
|
8
43
|
**新增**
|
package/FOR-AI.md
CHANGED
|
@@ -73,8 +73,8 @@ node tools/doctor.mjs --write # 生成 tools/local.json(已存在则不会
|
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
node tools/jev-verdict.mjs selftest # 期望 25/25
|
|
76
|
-
node tools/route.mjs selftest # 期望
|
|
77
|
-
node tools/route.mjs regress --file cases/route-cases-neutral.json # 期望
|
|
76
|
+
node tools/route.mjs selftest # 期望 44/44
|
|
77
|
+
node tools/route.mjs regress --file cases/route-cases-neutral.json # 期望 30/30,0 成本
|
|
78
78
|
node tools/route.mjs arms # 派发臂代理指标,期望 28/35 = 80.0%,0 成本
|
|
79
79
|
|
|
80
80
|
# 有密钥时再跑一次真机,确认端到端可用(约 $0.0003)
|
|
@@ -117,7 +117,7 @@ node tools/jev-verdict.mjs regress --file cases/injection-cases-neutral.json --c
|
|
|
117
117
|
node tools/route.mjs plan --task "核查一条社交媒体首发的传闻,需要国内外两侧交叉"
|
|
118
118
|
# → 看 ladders(该找哪些源)/ routes(走哪些渠道)/ failureActions(遇到 403、超时、0 结果怎么办)
|
|
119
119
|
# → 看 dispatchHint(要不要多路并行取证)
|
|
120
|
-
node tools/route.mjs regress --file cases/route-cases-neutral.json # 路由层回归,
|
|
120
|
+
node tools/route.mjs regress --file cases/route-cases-neutral.json # 路由层回归,30 例,0 成本
|
|
121
121
|
node tools/route.mjs arms # 派发臂代理指标(改触发词后必跑),0 成本
|
|
122
122
|
|
|
123
123
|
# ② 判据层(有密钥时):把"证据 → 结论"这件事交给决策模型
|
package/INSTRUCTIONS.md
CHANGED
|
@@ -99,6 +99,8 @@
|
|
|
99
99
|
| 社区/个人(论坛、问答、社交平台、博客) | 低(仅旁证/线索) |
|
|
100
100
|
| AI 生成内容 / 无法溯源内容 | 不采信 |
|
|
101
101
|
|
|
102
|
+
> **类型只是其中一条轴。** 同一来源还可能有利益关联,也可能处在大规模投毒污染的信息链上。这两项**不改变上表的权重、也不改变结论档位**——只按「利益相关与污染面」一节标注,并以双轨结论呈现(甲轨即本节档位)。
|
|
103
|
+
|
|
102
104
|
来源矛盾时**如实并列呈现**,说明分歧点(数据口径、时间线、立场),不做无依据的和稀泥。
|
|
103
105
|
|
|
104
106
|
**记录来源固定四要素**:①出处名称(站点/机构/作者)②来源类型(对照上表)③完整可点击 URL(不截断、不省略协议)④引用位置(标题、段落、表格、时间戳)。原文摘录加引号并注明"原文",转述则注明"转述"。
|
|
@@ -110,6 +112,7 @@
|
|
|
110
112
|
```markdown
|
|
111
113
|
## 一句话结论
|
|
112
114
|
**<已证实 / 很可能属实 / 未证实 / 证伪 / 无法核实>** · 置信度 <高 / 中 / 低>(依据:独立来源数量与权威性)
|
|
115
|
+
**乙轨(保守口径)**:<剔除标注源后重算的档位>(详见「利益相关与污染面」;上句为甲轨正式结论)
|
|
113
116
|
<2~3 行直给判断:哪些关键点成立、哪些不成立、哪些没查清>
|
|
114
117
|
**核查时间**:<日期>;**关键信息时效**:<信息本身的日期>
|
|
115
118
|
|
|
@@ -133,6 +136,16 @@
|
|
|
133
136
|
- 国外渠道:<搜到什么、口径如何> [n]
|
|
134
137
|
- 差异说明:<信息是否只在单侧出现、为何>
|
|
135
138
|
|
|
139
|
+
## 利益相关与污染面(标注,不参与定档)
|
|
140
|
+
**甲轨(默认口径,正式结论)**:<档位> —— 标注不参与定档
|
|
141
|
+
**乙轨(保守口径,剔除标注源后重算)**:<档位> —— <与甲轨的差在哪;两轨相同则写"两轨一致">
|
|
142
|
+
| 来源 | 层级 | 可观察依据 | 乙轨动作 |
|
|
143
|
+
|---|---|---|---|
|
|
144
|
+
| [n] | L1 / L2 | <文件、披露、所有权、历史口径一致性…> | 从"内容为真"的支撑源中剔除 |
|
|
145
|
+
- **污染面**:<哪一段若被投毒则全盘失效;首发时序 / 引用链形状 / 跨生态痕迹 / 结论冗余度四项各自的观察结果>
|
|
146
|
+
- **已隔离(L3)**:<无法检验的动机归因,及"现象相同 ⇒ 不可判定"的说明>
|
|
147
|
+
- **不降权声明**:以上均为标注;甲轨不因本节下调,乙轨是给读者的敏感性视图,不是本报告主张。
|
|
148
|
+
|
|
136
149
|
## 为什么会这样(可选,不适用则整节省略)
|
|
137
150
|
<关键分歧点、数据口径差异、时间线错位或传播机制的说明>
|
|
138
151
|
|
|
@@ -160,6 +173,61 @@
|
|
|
160
173
|
|
|
161
174
|
---
|
|
162
175
|
|
|
176
|
+
## 利益相关与污染面(标注制、不降权、双轨呈现)
|
|
177
|
+
|
|
178
|
+
**本节只标注,不降权。** 一个来源是否存在利益关联、是否处在大规模投毒污染的信息链上,**本技能不做判定**;它只把能拿出来看的东西标出来,并给出两套固定口径下的结论,由读报告的人自己裁定。
|
|
179
|
+
|
|
180
|
+
### 为什么不用降权(改之前先看这三条)
|
|
181
|
+
|
|
182
|
+
1. **非单调**——"没有替代源就不降权"这类条件降权,会让新增一条独立佐证反而触发降权、结论变差。"证据变多、档位变差"不可接受。
|
|
183
|
+
2. **奖励信息垄断**——若"唯一来源"能拿全权重,那么**确保别人无法核实**就是拿到高置信度的最优策略。这正是投毒与宣传想要的性质。
|
|
184
|
+
3. **全局降档**——投毒永远无法排除(连"无法排除"本身都无法排除)。一旦把它接进降档条件,等价于给整个技能统一减一档,判定力归零。
|
|
185
|
+
|
|
186
|
+
三条同源:**把"源的属性"当成了"结论的档位"**。所以本节只标注,档位仍按「信源不足的处理」③ 的独立源头数算。
|
|
187
|
+
|
|
188
|
+
### 标注三层
|
|
189
|
+
|
|
190
|
+
| 层级 | 判据 | 写进哪里 |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| **L1 客观可查** | 出资方 / 所有权 / 资助披露 / 监管文件 / 广告主集中度 / 作者利益申报——有文件就能引 | 标注表,带来源编号 |
|
|
193
|
+
| **L2 可推断** | 同类事件的历史口径一致性;"若此说为真,谁获益" | 标注表,**必须标明是推断** |
|
|
194
|
+
| **L3 不可判定** | 无法检验的动机归因("被 X 收买""是 Y 的代理人") | 只进**隔离区**;禁止进入标注表与结论 |
|
|
195
|
+
|
|
196
|
+
**L3 的机械化判据**:该指控成立与否,**能观察到的现象完全相同** ⇒ 不可判定 ⇒ 强制隔离。不靠"听起来像阴谋论"来判。
|
|
197
|
+
|
|
198
|
+
### 同一来源的两个角色必须分开
|
|
199
|
+
|
|
200
|
+
- **角色 A「它确实说过」**:事实级,**不受任何关联影响**。谁说的、原文是什么、何时说的,本身就可核实;"发布行为"可单独判「已证实」,不需要第三方佐证。
|
|
201
|
+
- **角色 B「所以说的是真的」**:受关联与污染影响的正是这一半,也是双轨要分开算的那一半。
|
|
202
|
+
|
|
203
|
+
**"官方发布" ≠ "内容为真"**:统计局发布 CPI,角色 A 证明"确实发布了这个数"(已证实),角色 B 证明"物价真涨了这个数"(受口径与发布方动机影响)。把两个问法混成"一手 = 可信",是这类判断出错的根源。
|
|
204
|
+
|
|
205
|
+
### 污染面:只声明攻击面,不承诺识别投毒
|
|
206
|
+
|
|
207
|
+
**单篇文本里看不出投毒**,能看的只有分布与时序。下面四项只用来**标出攻击面**,任一项异常都不构成"被投毒"的判定:
|
|
208
|
+
|
|
209
|
+
| 检查 | 看什么 |
|
|
210
|
+
|---|---|
|
|
211
|
+
| 首发时序 | 谁最早;是否早于它声称的"因" |
|
|
212
|
+
| 引用链形状 | N 条结果是 N 个上游,还是都指向同一个 seed、同时出现在大量低质镜像 |
|
|
213
|
+
| 跨生态痕迹 | 一侧有共识、另一侧零痕迹——必须与"审查 / 本地新闻"并列写出,**不作判据** |
|
|
214
|
+
| 结论冗余度 | 单条结论依赖几条互不共享上游的链;投毒成本随链数上升 |
|
|
215
|
+
|
|
216
|
+
**不可解的那一类要明说**:一手源本身被投毒(注册库、统计口径、监管公告造假)时,下游天然一致、冗余失效。这类只能在报告里承认"查不出",不能假装能查。
|
|
217
|
+
|
|
218
|
+
### 双轨结论(两套口径都要能复算)
|
|
219
|
+
|
|
220
|
+
标注不是免责声明,它必须落到两个**按固定规则算出来**的档位上:
|
|
221
|
+
|
|
222
|
+
- **甲轨(默认口径)**:标注**不参与定档**,即「信源不足的处理」③ 照算。**这是报告的正式结论。**
|
|
223
|
+
- **乙轨(保守口径)**:把标注表里 L1/L2 的源,以及污染面中"若被投毒则该段失效"的条目,**从"支撑内容为真"的独立源头集合中剔除**后重算档位。L3 不参与重算(没有可观察对象)。若某事实点的支撑源全部落在标注表里,乙轨该点就是「无法核实」——这正是要给读者看的东西。
|
|
224
|
+
|
|
225
|
+
**两轨并列呈现,差额本身就是信息**:甲轨高、乙轨低 ⇒ 结论依赖那些被标注的源;两轨相同 ⇒ 关联与污染面不影响这个结论。**不写"我更倾向哪一轨"**——那是读者的判断,不是技能的。
|
|
226
|
+
|
|
227
|
+
**成本控制**:标注表为空时,报告里一行写"未发现可标注的利益关联与污染面,两轨一致",不展开。
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
163
231
|
## 可选增强:把结构化判断交给决策模型
|
|
164
232
|
|
|
165
233
|
若你的环境里有一个"输入状态 + 结构化问题、返回带类型答案与概率"的决策模型(本包工具默认对接 TypeSafe System One 协议,端点/模型可配置),可以用它替代人来做三类**事实性**判断:
|
|
@@ -213,6 +281,8 @@
|
|
|
213
281
|
|
|
214
282
|
单一来源**永远不写成"已证实"**,只能进旁注或"局限与待核实"。
|
|
215
283
|
|
|
284
|
+
**本节档位只看独立源头数。** 利益相关与污染面**不参与**这个计算,也不改变它算出的档位——它们另行按「利益相关与污染面」标注并双轨呈现(甲轨就是本节档位)。
|
|
285
|
+
|
|
216
286
|
**④ 报告如实呈现缺口**:在"局限与待核实"写明——哪个事实点不足、缺到什么程度、为什么(时效太新 / 题材敏感 / 封闭生态 / 登录墙反爬)、已尝试哪些渠道;并给出可操作建议(如"等主流媒体跟进或官方回应后再确认")。
|
|
217
287
|
|
|
218
288
|
**红线**:信源不足时禁止用内部知识/推测填充,禁止编造来源。**搜不到 ≠ 不存在**(尤其国内封闭生态),如实标注"公开渠道未检索到"。
|
|
@@ -229,6 +299,8 @@
|
|
|
229
299
|
| 封闭生态 | 不涉及 | 涉及公众号 / 知乎 / 视频站 / Reddit / 微博等需逐渠道专门取正文 |
|
|
230
300
|
| 用户口径 | "简单查一下""快点看看" | 明确要"彻底核查""多找些资料" |
|
|
231
301
|
|
|
302
|
+
**兜底域不等于简单任务**:`plan` 输出里 `fallback: true` 表示没有命中任何具体事实类型、给的是 `general_fact` 通用阶梯;`closed=false` 只说明「尚未识别出封闭生态」,不代表任务简单。此时仍按上表逐条判,**任一命中右列即派**。(1.5.1 修的正是这处:早期版本把未识别任务兜底到软件发布域 tech_release,并提示「单路可覆盖」,把该派的任务劝退了。)
|
|
303
|
+
|
|
232
304
|
四种走法:
|
|
233
305
|
|
|
234
306
|
- **轻量直连**:主对话自己多路搜索 + 抓取,本轮内出结论。**轻量 ≠ 降标准**——多源交叉、国内外并行、来源四要素等铁律全部照旧,只是不拆子代理。
|
|
@@ -242,8 +314,18 @@
|
|
|
242
314
|
- 需要核实的事实点;
|
|
243
315
|
- **必须遵守的规则**:多源交叉、来源固定四要素(出处名 / 来源类型 / 完整可点击 URL / 引用位置)、原文摘录加引号标"原文"否则标"转述"、配一条质疑词反查、抓不到就如实写"未能获取"而不许编造;
|
|
244
316
|
- **该渠道的具体抓取手段**(如"Reddit 走 `.json` 端点""视频站走字幕/弹幕工具""X 走 syndication 接口"),避免子代理在登录墙上空转。
|
|
317
|
+
- **「引文净化」约定必须写进派发 prompt**(见下节「回报的引文净化」):子代理的最终回报会经过内容审核,逐字复述辱称或族群贬损文本可能让**整条回报被丢弃**,那一路渠道的证据就全丢了。
|
|
318
|
+
|
|
319
|
+
### 回报的引文净化
|
|
320
|
+
|
|
321
|
+
极端题材(族群冲突、辱骂、暴力内容)里,逐字引文既有**失真风险**(转述链上被裁剪成更冒犯的版本)也有**丢回报风险**。回报时统一按这两档处理:
|
|
322
|
+
|
|
323
|
+
- **事实性表述照常逐字引**——时间、账号名、tweet_id、互动量、可观察行为特征(建号时间、发帖节奏、是否模板化),以及任何不含贬损的中性陈述;
|
|
324
|
+
- **贬损性 / 辱骂性原文不逐字复述**——改为**分类描述 + 定位信息**:`该帖含针对特定族群的贬损表述`(或"人身侮辱""辱华/辱土"这类中性的性质标签)+ **原帖 URL + tweet_id + 发布时间**。需要逐字文本时由主对话自己调 syndication / oembed 接口取,不经子代理回报。
|
|
325
|
+
|
|
326
|
+
**这是「原文摘录加引号并注明"原文"」规则在极端题材上的例外**:不引脏文本,但替代它的定位信息必须齐全,否则等于没给证据。这也不是软化结论——**性质、来源、定位信息一个不少**,少的是可被断章引用的原始脏文本;而"存在辱骂"这一事实本身,分类描述 + 可点击 URL 已经足够,且更经得起复核。极端题材建议按渠道数**多派一路冗余**(3→4):某条回报若被整条丢弃,证据不至于全失。
|
|
245
327
|
|
|
246
|
-
**回报**:每个子代理回报时须标注**来源同源性**(如"本渠道 6 条结果均转载自同一篇首发"
|
|
328
|
+
**回报**:每个子代理回报时须标注**来源同源性**(如"本渠道 6 条结果均转载自同一篇首发"),主对话才能正确计算独立源头数。回报**第一行写渠道状态**——`渠道状态:已取证 / 无命中 / 抓取失败`——主对话才能区分「这条渠道确实没有证据」与「这条渠道的回报丢了」,不至于把后者当成前者直接降档。**回报结构统一**:
|
|
247
329
|
|
|
248
330
|
```
|
|
249
331
|
渠道 → 命中来源清单(带四要素)→ 与主线是否一致 / 矛盾 → 抓取失败的渠道及原因
|
|
@@ -263,6 +345,7 @@
|
|
|
263
345
|
- **环境相关的值只放 `tools/local.json`**(模板 `tools/local.example.json`):密钥、端点、state 目录、数据表里的 `${占位符}`,以及可选的能力绑定 `capabilities`、输出约定 `outputConvention`、运行时基线 `runtimeNotes`。代码与数据表**不写死任何主机路径**,`selftest` 里有断言在守这条。
|
|
264
346
|
- **不要在本技能正文里写入任何主机、内网地址、路径或密钥**。本机事实要么进 `local.json`,要么作为"在某环境测得"的证据进 `MEASUREMENTS.md`。
|
|
265
347
|
- **版本纪律**:凡是改动面向使用者的行为(流程、报告模板、判据、触发词),就升 frontmatter 的 `version` 并在 `CHANGELOG.md` 记一条净变化;只改措辞或文档不算。
|
|
348
|
+
- **「利益相关与污染面」是标注制,不是降权制**:不要把任何"利益相关 / 疑似投毒 ⇒ 降档"的规则接进定档。至少会同时坏三件事(非单调、奖励信息垄断、全局降档),三条理由是那一节的正文,改之前先重读。
|
|
266
349
|
- 改文件前先备份;改完跑:`node tools/smoke-plugin.mjs`(插件挂载与单一真相源)、`node tools/doctor.mjs`(需要时加 `--net`)、`node tools/jev-verdict.mjs selftest`、`node tools/route.mjs selftest`、以及受影响的 `regress`。改了本文件还要重跑 `node tools/make-instructions.mjs` 同步 `INSTRUCTIONS.md`(它是生成物)。
|
|
267
350
|
|
|
268
351
|
## 使用边界
|
package/MEASUREMENTS.md
CHANGED
|
@@ -114,8 +114,8 @@
|
|
|
114
114
|
node tools/doctor.mjs # 先看本机能力与降级路径
|
|
115
115
|
node tools/doctor.mjs --net # 再真跑一遍抓取链与端点自测
|
|
116
116
|
node tools/jev-verdict.mjs selftest # 25 项离线断言,不花钱
|
|
117
|
-
node tools/route.mjs selftest #
|
|
118
|
-
node tools/route.mjs regress --file cases/route-cases-neutral.json # 路由语料
|
|
117
|
+
node tools/route.mjs selftest # 44 项离线断言,不花钱
|
|
118
|
+
node tools/route.mjs regress --file cases/route-cases-neutral.json # 路由语料 30 例,不花钱
|
|
119
119
|
node tools/route.mjs arms # 派发臂代理指标(§4.1),不花钱
|
|
120
120
|
|
|
121
121
|
# 本包自带的是(第二遍)去痕版语料
|
|
@@ -140,4 +140,5 @@ node tools/jev-verdict.mjs regress --file cases/sufficient-cases-neutral.json
|
|
|
140
140
|
7. **`contradicted` ≠ 证伪**:`p < 0.5` 的档位里确实混着真值为"支持"的样本(§1.2),对外只能表述为"证据不足或被反驳,需人工复核"。
|
|
141
141
|
8. **域路由的触发词是正则,必然有误命中**:`tech_release` 的词表里有「发布」,会把「政策发布会」这类任务拉进技术域(实测 dispatch 语料 D27 因此同时命中 5 个域);`medical` 的单字「药」会把「农药残留」同时拉进医疗域。多命中**不影响结论正确性**(多一个域只是多给几条来源阶梯),但会推高 `dispatchHint` 的域数阈值。1.3.0 新增七个域时按「具体在前」排列以降低串味,既有域的**触发词**一个未动。1.3.0 另修了 `medical` 的**域路由**:原先指向 `official_json_api`(国务院政策文件库 / 法规库),与它阶梯首级的「药品监管机构批准信息」对不上,已改走 `gov_notice`(含国家药监局与市场监管总局)。
|
|
142
142
|
9. **`factPointsInText` 不是真的拆事实点**:它只数任务文本里 `;;。\n` 的个数再 +1,却被 `dispatchHint` 当判据用(`>= 4` 就建议派发)。一段逗号连写的长任务会被低估,一段分号并列的短任务会被高估。它只够当粗筛,不要拿它当「事实点已拆好」的证据。
|
|
143
|
+
10. **路由的兜底域(1.5.1 修)**:未命中任何触发词的任务原先兜底到 `tech_release`——那是「官方仓库 / 包管理器元数据」的阶梯,与多数任务无关;而且该域 `closed=false`,`dispatchHint` 会说「单路可覆盖,串行处理即可」,把「封闭生态 / 大量长文」这类真正该派的任务劝退。现改为专用 `general_fact` 兜底阶梯(当事方原始发布 → 通讯社 → 元搜索交叉 → 存档 → 当地媒体 → 社区线索),`plan` 输出新增 `fallback`,兜底时提示改为「按 SKILL.md 的信号表判断」。同一轮补了两条触发词(`cn_social_rumor`:推特 / Twitter / X 平台 / 骂战 / 对线 / 论战 / 口水战 / 开撕 / 网络战;`international`:土耳其 / 希腊 / 俄罗斯 / 越南 / 印度 / 韩国 / 朝鲜 / 以色列 / 巴勒斯坦 / 乌克兰 / 阿根廷 / 巴西 / 墨西哥 / 沙特 / 埃及)。按 §4.1 的代理指标重跑,**28/35 = 80.0% 与 7 条 mismatch(D08 / D10 / D12 / D15 / D27 / D30 / D37)逐条不变**——新增词条在 35 条共识样本上没改变任何一条判定;样本小,这只说明「未变差」,不等于扩词已在通用任务上验证。
|
|
143
144
|
|
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
[](https://github.com/7starsseeker/dsh-fact-check/stargazers)
|
|
14
14
|
[](https://github.com/7starsseeker/dsh-fact-check/issues)
|
|
15
15
|
[](./CONTRIBUTING.md)
|
|
16
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
16
17
|
|
|
17
18
|
> A fact-checking skill for DeepSeek Harness that verifies claims against the open web instead of model
|
|
18
19
|
> memory — multi-source cross-checking, domestic and international search ecosystems in parallel,
|
|
@@ -67,7 +68,7 @@ are kept in their own sections — *unverified* and *undecidable* never sit in t
|
|
|
67
68
|
The skill body is not bound to any host, product or tool chain: it names *capabilities*, and
|
|
68
69
|
[`ADAPTING.md`](./ADAPTING.md) maps them onto your environment.
|
|
69
70
|
|
|
70
|
-
**Verified hosts: DSH 0.1.7-rc.2, 0.2.0-rc.2 and 0.2.1-rc.
|
|
71
|
+
**Verified hosts: DSH 0.1.7-rc.2, 0.2.0-rc.2, 0.2.1-rc.2 and 0.2.1-rc.3.** DSH 0.1.7-rc.2 was checked end to end on 2026-09-25 (Node 24.21.0, WSL/Linux): the host discovers the skill
|
|
71
72
|
and loads its body; the plugin form mounts on the host's own skill registry with `source: bundled`, its
|
|
72
73
|
description read from `SKILL.md` and `get()` returning that body verbatim; `npm run selftest` passes
|
|
73
74
|
(plugin mount 27/27, `jev-verdict` 25/25, `route` 37/37); `route.mjs regress` is 26/26 offline; and the
|
|
@@ -82,6 +83,8 @@ forbidden.
|
|
|
82
83
|
|
|
83
84
|
**DSH 0.2.1-rc.2 was checked end to end on 2026-10-17** (Node 24.21.0, Windows). The registry implementation (`@deepseek-ai/dsh-skill`'s `lib/index.js`) has **no content change** between 0.2.0-rc.2 and 0.2.1-rc.2 — the diff is line endings and version metadata only (`package.json` bumps the peers to cordis `~4.0.5` and adds a `./locale/*.json` export) — so no API adaptation was needed. What did change is what a provider may do with `control`, and this package now uses both 0.2.1 affordances: the candidate carries `path` (the absolute `SKILL.md`, retained in catalog summaries), and the provider watches `SKILL.md` and calls `control.invalidate()` on save, so editing the body refreshes the session catalog without a restart (150 ms debounce; the watcher is torn down on `control.signal` abort or context dispose, and a host that passes no `control` keeps the previous "restart to re-read" behavior). Evidence: the plugin was mounted on the host's own `0.2.1-rc.2` registry code (taken from the shipped asar, wired with the host's own cordis 4.0.5) and on the **published** `0.2.0-rc.2` package — 21/21 checks on each, `snapshot.complete === true`, `get()` returning the body verbatim, `provider.list()` rank 600, and both edit→refresh cycles observed; `npm run selftest` 27/27, 25/25, 37/37 and `route.mjs regress` 26/26 re-run on Node 24.21.0.
|
|
84
85
|
|
|
86
|
+
**DSH 0.2.1-rc.3 was checked on 2026-10-24** (Node 24.22.1, Windows). Nothing in the registry contract moved: `@deepseek-ai/dsh-skill` 0.2.1-rc.3 still exports `BUNDLED_SKILL_RANK` (600), `SkillRegistry`, `isSkillName`, `isModelInvocable` and `isUserInvocable`, still hands `registerProvider()` the same `control` (`{ signal, invalidate }`), and `invalidateCache()` still advances the cache revision and broadcasts `skills/change`. The plugin was mounted on that registry — taken from the shipped `app.asar`, wired with the host's own cordis 4.0.5 — and passed **28/28** checks: `inject: ['skills']`; the candidate carrying `source: bundled`, `rank` 600 equal to the host's own exported constant, the absolute `SKILL.md` as `path`, the package root as `resourceBase`, and the frontmatter description verbatim; `get()` returning the body (13,533 characters, frontmatter stripped, `path` retained); `control.invalidate()` advancing the registry revision 1 → 2 and emitting exactly one `skills/change`; and disposal removing the provider and aborting `control.signal`. Two details worth writing down because they look like failures and are not: the host's `toSummary()` deliberately drops `rank` from catalog summaries (it is a same-name arbitration input, not a display field), and registration only becomes observable once `ctx.plugin()`'s thenable resolves — inspected before that await, even a successful mount shows no `control`. In this same rc3 session the **directory** form is the one that runs (the host's own skill directory), and the session's skill catalog lists `fact-check` with this repository's `SKILL.md` description.
|
|
87
|
+
|
|
85
88
|
## Install
|
|
86
89
|
|
|
87
90
|
### As a DSH plugin
|
|
@@ -128,7 +131,7 @@ Two optional offline tools sit alongside it:
|
|
|
128
131
|
|
|
129
132
|
| Tool | What it does |
|
|
130
133
|
|---|---|
|
|
131
|
-
| `node tools/route.mjs plan --task "…"` | Deterministic planning: which source ladder and which channels this kind of claim needs, plus the failure-action table. A pure data table — no model, no tokens. |
|
|
134
|
+
| `node tools/route.mjs plan --task "…"` | Deterministic planning: which source ladder and which channels this kind of claim needs, plus the failure-action table. A pure data table — no model, no tokens. A claim that matches no known fact type still gets the general fact-check ladder (flagged `fallback: true` in the output), never a software-release one. |
|
|
132
135
|
| `node tools/jev-verdict.mjs` | The judgement client described below. |
|
|
133
136
|
|
|
134
137
|
## The optional Jev decision layer
|
|
@@ -171,7 +174,7 @@ node tools/doctor.mjs # what this machine can and
|
|
|
171
174
|
|
|
172
175
|
`node tools/doctor.mjs --net` additionally self-tests the fetch chains and the judgement endpoint, and
|
|
173
176
|
reports which capabilities are missing and how the skill degrades without them. Current status on this
|
|
174
|
-
checkout: **27/27**, **25/25**, **
|
|
177
|
+
checkout: **27/27**, **25/25**, **44/44** and **30/30** assertions pass.
|
|
175
178
|
|
|
176
179
|
CI runs exactly these commands on Linux and Windows, on Node 18 and 22, plus one more check: that the
|
|
177
180
|
generated `INSTRUCTIONS.md` still matches `SKILL.md`.
|
package/README.zh-CN.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
[](https://github.com/7starsseeker/dsh-fact-check/stargazers)
|
|
14
14
|
[](https://github.com/7starsseeker/dsh-fact-check/issues)
|
|
15
15
|
[](./CONTRIBUTING.md)
|
|
16
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
16
17
|
|
|
17
18
|
> DeepSeek Harness 用的事实核查技能:不轻信模型自己的记忆,一律去公开互联网核实——多源交叉、
|
|
18
19
|
> 国内外信息生态并行、对抗性反查,最后交出一份结论先行、每条论断都可溯源的核查报告。
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
技能正文不绑定任何产品、主机或工具链:它只写**能力名**,由 [`ADAPTING.md`](./ADAPTING.md) 把能力
|
|
62
63
|
落到你的环境里。
|
|
63
64
|
|
|
64
|
-
**已验证宿主:DSH 0.1.7-rc.2、0.2.0-rc.2 与 0.2.1-rc.
|
|
65
|
+
**已验证宿主:DSH 0.1.7-rc.2、0.2.0-rc.2、0.2.1-rc.2 与 0.2.1-rc.3。** 0.1.7-rc.2 于 2026-09-25 完整跑过一遍(Node 24.21.0,WSL/Linux):宿主能发现本技能并读入正文;
|
|
65
66
|
插件形态能挂到宿主自己的技能注册表上,`source: bundled`,描述取自 `SKILL.md`,`get()` 交出的正文
|
|
66
67
|
与 `SKILL.md` 逐字一致;`npm run selftest` 全过(插件挂载 27/27、`jev-verdict` 25/25、`route` 37/37);
|
|
67
68
|
`route.mjs regress` 离线 26/26;判据语料复现 [`MEASUREMENTS.md`](./MEASUREMENTS.md) §6 的预期 ——
|
|
@@ -74,6 +75,8 @@
|
|
|
74
75
|
|
|
75
76
|
**DSH 0.2.1-rc.2 于 2026-10-17 完整跑过一遍**(Node 24.21.0,Windows)。注册表的实现(`@deepseek-ai/dsh-skill` 的 `lib/index.js`)在 0.2.0-rc.2 与 0.2.1-rc.2 之间**内容没有变化** —— diff 只有换行符与版本号(`package.json` 把 peer 依赖抬到 cordis `~4.0.5`、加了一个 `./locale/*.json` 导出)—— 所以不需要任何 API 适配。变的是 provider 能拿 `control` **做什么**,本包两样都用上了:候选带上 `path`(指向绝对的 `SKILL.md`,摘要会保留它);provider 监听 `SKILL.md`,保存时调 `control.invalidate()`,改正文不必重启就会刷新会话里的技能目录(150 ms 去抖;`control.signal` abort 或上下文销毁时收尾,宿主不传 `control` 时退化为「改完重启生效」)。证据:插件分别挂到宿主自己那套 `0.2.1-rc.2` 注册表代码(从已发布的 asar 里取出,配宿主自带的 cordis 4.0.5)与**已发布**的 `0.2.0-rc.2` 包上,各 21/21 项检查通过:`snapshot.complete === true`、`get()` 交出的正文与 `SKILL.md` 逐字一致、`provider.list()` 的 rank 为 600,两轮「改文件 → 目录自动刷新」都观察到了;`npm run selftest` 27/27、25/25、37/37 与 `route.mjs regress` 26/26 均在 Node 24.21.0 上复跑。
|
|
76
77
|
|
|
78
|
+
**DSH 0.2.1-rc.3 于 2026-10-24 完整跑过一遍**(Node 24.22.1,Windows)。注册表契约没有位移:`@deepseek-ai/dsh-skill` 0.2.1-rc.3 仍导出 `BUNDLED_SKILL_RANK`(600)、`SkillRegistry`、`isSkillName`、`isModelInvocable` 与 `isUserInvocable`,`registerProvider()` 交出的 `control`(`{ signal, invalidate }`)不变,`invalidateCache()` 仍推进缓存 revision 并广播 `skills/change`。插件挂在这套注册表上(取自随宿主发布的 `app.asar`,配宿主自己的 cordis 4.0.5)通过了 **28/28** 项检查:`inject: ['skills']`;候选带 `source: bundled`、`rank` 600 等于宿主导出的常量、绝对 `SKILL.md` 作为 `path`、包根目录作为 `resourceBase`、描述与 frontmatter 逐字一致;`get()` 交出正文(13,533 字符,frontmatter 已剥离,`path` 保留);`control.invalidate()` 让注册表 revision 从 1 到 2 并恰好广播一次 `skills/change`;拆卸后 provider 消失且 `control.signal` 已 abort。两处看着像失败、其实不是的细节也一并记下:宿主的 `toSummary()` 有意不在目录摘要里带 `rank`(它是同名仲裁的输入,不是展示字段);注册只在 `ctx.plugin()` 的 thenable 落定后可观测 —— 在 await 之前去看,即便挂载成功也看不到 `control`。同一次 rc3 会话里真正运行的是**目录形态**(宿主自己的技能目录),会话的技能目录用本仓 `SKILL.md` 的描述列出了 `fact-check`。
|
|
79
|
+
|
|
77
80
|
## 安装
|
|
78
81
|
|
|
79
82
|
### 作为 DSH 插件
|
|
@@ -118,7 +121,7 @@ dsh plugin add ./dsh-fact-check
|
|
|
118
121
|
|
|
119
122
|
| 工具 | 做什么 |
|
|
120
123
|
|---|---|
|
|
121
|
-
| `node tools/route.mjs plan --task "…"` | 确定性规划:这类核查该走哪条来源阶梯、哪些渠道,以及失败动作表。纯数据表,无模型、0 token
|
|
124
|
+
| `node tools/route.mjs plan --task "…"` | 确定性规划:这类核查该走哪条来源阶梯、哪些渠道,以及失败动作表。纯数据表,无模型、0 token。未命中任何已知事实类型的任务也照样给阶梯——给的是通用事实核查阶梯(输出里 `fallback: true`),不会是软件发布那套。 |
|
|
122
125
|
| `node tools/jev-verdict.mjs` | 下面说的判据客户端。 |
|
|
123
126
|
|
|
124
127
|
## 可选的 Jev 判据层
|
|
@@ -156,7 +159,7 @@ node tools/doctor.mjs # 这台机器能做什么
|
|
|
156
159
|
```
|
|
157
160
|
|
|
158
161
|
`node tools/doctor.mjs --net` 会额外自测抓取链与判据端点,并报告缺哪些能力、缺了会降级成什么样。
|
|
159
|
-
本检出上的当前状态:**27/27**、**25/25**、**
|
|
162
|
+
本检出上的当前状态:**27/27**、**25/25**、**44/44**、**30/30** 断言全过。
|
|
160
163
|
|
|
161
164
|
CI 在 Linux 与 Windows 上、Node 18 与 22 下跑的就是上面这几条,另外多一条检查:生成的
|
|
162
165
|
`INSTRUCTIONS.md` 是否仍然与 `SKILL.md` 一致。
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fact-check
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.5.1
|
|
4
4
|
description: 事实核查与资料搜索。当用户要求核实事实/传闻/新闻/数据/情况的真伪、查证信息、确认现状、补充资料时使用——即使用户只说了"查一下""确认一下""核实""这是不是真的""帮我看看",也应触发。核心行为:不依赖自身知识库,所有关键信息一律通过互联网搜索获取,搜索途径与信息来源尽量多样以便交叉核实,并同时覆盖国内与国外信息生态。执行模式按工作量自动选择:轻量核查由主对话直连完成,渠道多或需抓取大量长文时自动分派并行子代理。
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -100,6 +100,8 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
100
100
|
| 社区/个人(论坛、问答、社交平台、博客) | 低(仅旁证/线索) |
|
|
101
101
|
| AI 生成内容 / 无法溯源内容 | 不采信 |
|
|
102
102
|
|
|
103
|
+
> **类型只是其中一条轴。** 同一来源还可能有利益关联,也可能处在大规模投毒污染的信息链上。这两项**不改变上表的权重、也不改变结论档位**——只按「利益相关与污染面」一节标注,并以双轨结论呈现(甲轨即本节档位)。
|
|
104
|
+
|
|
103
105
|
来源矛盾时**如实并列呈现**,说明分歧点(数据口径、时间线、立场),不做无依据的和稀泥。
|
|
104
106
|
|
|
105
107
|
**记录来源固定四要素**:①出处名称(站点/机构/作者)②来源类型(对照上表)③完整可点击 URL(不截断、不省略协议)④引用位置(标题、段落、表格、时间戳)。原文摘录加引号并注明"原文",转述则注明"转述"。
|
|
@@ -111,6 +113,7 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
111
113
|
```markdown
|
|
112
114
|
## 一句话结论
|
|
113
115
|
**<已证实 / 很可能属实 / 未证实 / 证伪 / 无法核实>** · 置信度 <高 / 中 / 低>(依据:独立来源数量与权威性)
|
|
116
|
+
**乙轨(保守口径)**:<剔除标注源后重算的档位>(详见「利益相关与污染面」;上句为甲轨正式结论)
|
|
114
117
|
<2~3 行直给判断:哪些关键点成立、哪些不成立、哪些没查清>
|
|
115
118
|
**核查时间**:<日期>;**关键信息时效**:<信息本身的日期>
|
|
116
119
|
|
|
@@ -134,6 +137,16 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
134
137
|
- 国外渠道:<搜到什么、口径如何> [n]
|
|
135
138
|
- 差异说明:<信息是否只在单侧出现、为何>
|
|
136
139
|
|
|
140
|
+
## 利益相关与污染面(标注,不参与定档)
|
|
141
|
+
**甲轨(默认口径,正式结论)**:<档位> —— 标注不参与定档
|
|
142
|
+
**乙轨(保守口径,剔除标注源后重算)**:<档位> —— <与甲轨的差在哪;两轨相同则写"两轨一致">
|
|
143
|
+
| 来源 | 层级 | 可观察依据 | 乙轨动作 |
|
|
144
|
+
|---|---|---|---|
|
|
145
|
+
| [n] | L1 / L2 | <文件、披露、所有权、历史口径一致性…> | 从"内容为真"的支撑源中剔除 |
|
|
146
|
+
- **污染面**:<哪一段若被投毒则全盘失效;首发时序 / 引用链形状 / 跨生态痕迹 / 结论冗余度四项各自的观察结果>
|
|
147
|
+
- **已隔离(L3)**:<无法检验的动机归因,及"现象相同 ⇒ 不可判定"的说明>
|
|
148
|
+
- **不降权声明**:以上均为标注;甲轨不因本节下调,乙轨是给读者的敏感性视图,不是本报告主张。
|
|
149
|
+
|
|
137
150
|
## 为什么会这样(可选,不适用则整节省略)
|
|
138
151
|
<关键分歧点、数据口径差异、时间线错位或传播机制的说明>
|
|
139
152
|
|
|
@@ -161,6 +174,61 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
161
174
|
|
|
162
175
|
---
|
|
163
176
|
|
|
177
|
+
## 利益相关与污染面(标注制、不降权、双轨呈现)
|
|
178
|
+
|
|
179
|
+
**本节只标注,不降权。** 一个来源是否存在利益关联、是否处在大规模投毒污染的信息链上,**本技能不做判定**;它只把能拿出来看的东西标出来,并给出两套固定口径下的结论,由读报告的人自己裁定。
|
|
180
|
+
|
|
181
|
+
### 为什么不用降权(改之前先看这三条)
|
|
182
|
+
|
|
183
|
+
1. **非单调**——"没有替代源就不降权"这类条件降权,会让新增一条独立佐证反而触发降权、结论变差。"证据变多、档位变差"不可接受。
|
|
184
|
+
2. **奖励信息垄断**——若"唯一来源"能拿全权重,那么**确保别人无法核实**就是拿到高置信度的最优策略。这正是投毒与宣传想要的性质。
|
|
185
|
+
3. **全局降档**——投毒永远无法排除(连"无法排除"本身都无法排除)。一旦把它接进降档条件,等价于给整个技能统一减一档,判定力归零。
|
|
186
|
+
|
|
187
|
+
三条同源:**把"源的属性"当成了"结论的档位"**。所以本节只标注,档位仍按「信源不足的处理」③ 的独立源头数算。
|
|
188
|
+
|
|
189
|
+
### 标注三层
|
|
190
|
+
|
|
191
|
+
| 层级 | 判据 | 写进哪里 |
|
|
192
|
+
|---|---|---|
|
|
193
|
+
| **L1 客观可查** | 出资方 / 所有权 / 资助披露 / 监管文件 / 广告主集中度 / 作者利益申报——有文件就能引 | 标注表,带来源编号 |
|
|
194
|
+
| **L2 可推断** | 同类事件的历史口径一致性;"若此说为真,谁获益" | 标注表,**必须标明是推断** |
|
|
195
|
+
| **L3 不可判定** | 无法检验的动机归因("被 X 收买""是 Y 的代理人") | 只进**隔离区**;禁止进入标注表与结论 |
|
|
196
|
+
|
|
197
|
+
**L3 的机械化判据**:该指控成立与否,**能观察到的现象完全相同** ⇒ 不可判定 ⇒ 强制隔离。不靠"听起来像阴谋论"来判。
|
|
198
|
+
|
|
199
|
+
### 同一来源的两个角色必须分开
|
|
200
|
+
|
|
201
|
+
- **角色 A「它确实说过」**:事实级,**不受任何关联影响**。谁说的、原文是什么、何时说的,本身就可核实;"发布行为"可单独判「已证实」,不需要第三方佐证。
|
|
202
|
+
- **角色 B「所以说的是真的」**:受关联与污染影响的正是这一半,也是双轨要分开算的那一半。
|
|
203
|
+
|
|
204
|
+
**"官方发布" ≠ "内容为真"**:统计局发布 CPI,角色 A 证明"确实发布了这个数"(已证实),角色 B 证明"物价真涨了这个数"(受口径与发布方动机影响)。把两个问法混成"一手 = 可信",是这类判断出错的根源。
|
|
205
|
+
|
|
206
|
+
### 污染面:只声明攻击面,不承诺识别投毒
|
|
207
|
+
|
|
208
|
+
**单篇文本里看不出投毒**,能看的只有分布与时序。下面四项只用来**标出攻击面**,任一项异常都不构成"被投毒"的判定:
|
|
209
|
+
|
|
210
|
+
| 检查 | 看什么 |
|
|
211
|
+
|---|---|
|
|
212
|
+
| 首发时序 | 谁最早;是否早于它声称的"因" |
|
|
213
|
+
| 引用链形状 | N 条结果是 N 个上游,还是都指向同一个 seed、同时出现在大量低质镜像 |
|
|
214
|
+
| 跨生态痕迹 | 一侧有共识、另一侧零痕迹——必须与"审查 / 本地新闻"并列写出,**不作判据** |
|
|
215
|
+
| 结论冗余度 | 单条结论依赖几条互不共享上游的链;投毒成本随链数上升 |
|
|
216
|
+
|
|
217
|
+
**不可解的那一类要明说**:一手源本身被投毒(注册库、统计口径、监管公告造假)时,下游天然一致、冗余失效。这类只能在报告里承认"查不出",不能假装能查。
|
|
218
|
+
|
|
219
|
+
### 双轨结论(两套口径都要能复算)
|
|
220
|
+
|
|
221
|
+
标注不是免责声明,它必须落到两个**按固定规则算出来**的档位上:
|
|
222
|
+
|
|
223
|
+
- **甲轨(默认口径)**:标注**不参与定档**,即「信源不足的处理」③ 照算。**这是报告的正式结论。**
|
|
224
|
+
- **乙轨(保守口径)**:把标注表里 L1/L2 的源,以及污染面中"若被投毒则该段失效"的条目,**从"支撑内容为真"的独立源头集合中剔除**后重算档位。L3 不参与重算(没有可观察对象)。若某事实点的支撑源全部落在标注表里,乙轨该点就是「无法核实」——这正是要给读者看的东西。
|
|
225
|
+
|
|
226
|
+
**两轨并列呈现,差额本身就是信息**:甲轨高、乙轨低 ⇒ 结论依赖那些被标注的源;两轨相同 ⇒ 关联与污染面不影响这个结论。**不写"我更倾向哪一轨"**——那是读者的判断,不是技能的。
|
|
227
|
+
|
|
228
|
+
**成本控制**:标注表为空时,报告里一行写"未发现可标注的利益关联与污染面,两轨一致",不展开。
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
164
232
|
## 可选增强:把结构化判断交给决策模型
|
|
165
233
|
|
|
166
234
|
若你的环境里有一个"输入状态 + 结构化问题、返回带类型答案与概率"的决策模型(本包工具默认对接 TypeSafe System One 协议,端点/模型可配置),可以用它替代人来做三类**事实性**判断:
|
|
@@ -214,6 +282,8 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
214
282
|
|
|
215
283
|
单一来源**永远不写成"已证实"**,只能进旁注或"局限与待核实"。
|
|
216
284
|
|
|
285
|
+
**本节档位只看独立源头数。** 利益相关与污染面**不参与**这个计算,也不改变它算出的档位——它们另行按「利益相关与污染面」标注并双轨呈现(甲轨就是本节档位)。
|
|
286
|
+
|
|
217
287
|
**④ 报告如实呈现缺口**:在"局限与待核实"写明——哪个事实点不足、缺到什么程度、为什么(时效太新 / 题材敏感 / 封闭生态 / 登录墙反爬)、已尝试哪些渠道;并给出可操作建议(如"等主流媒体跟进或官方回应后再确认")。
|
|
218
288
|
|
|
219
289
|
**红线**:信源不足时禁止用内部知识/推测填充,禁止编造来源。**搜不到 ≠ 不存在**(尤其国内封闭生态),如实标注"公开渠道未检索到"。
|
|
@@ -230,6 +300,8 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
230
300
|
| 封闭生态 | 不涉及 | 涉及公众号 / 知乎 / 视频站 / Reddit / 微博等需逐渠道专门取正文 |
|
|
231
301
|
| 用户口径 | "简单查一下""快点看看" | 明确要"彻底核查""多找些资料" |
|
|
232
302
|
|
|
303
|
+
**兜底域不等于简单任务**:`plan` 输出里 `fallback: true` 表示没有命中任何具体事实类型、给的是 `general_fact` 通用阶梯;`closed=false` 只说明「尚未识别出封闭生态」,不代表任务简单。此时仍按上表逐条判,**任一命中右列即派**。(1.5.1 修的正是这处:早期版本把未识别任务兜底到软件发布域 tech_release,并提示「单路可覆盖」,把该派的任务劝退了。)
|
|
304
|
+
|
|
233
305
|
四种走法:
|
|
234
306
|
|
|
235
307
|
- **轻量直连**:主对话自己多路搜索 + 抓取,本轮内出结论。**轻量 ≠ 降标准**——多源交叉、国内外并行、来源四要素等铁律全部照旧,只是不拆子代理。
|
|
@@ -243,8 +315,18 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
243
315
|
- 需要核实的事实点;
|
|
244
316
|
- **必须遵守的规则**:多源交叉、来源固定四要素(出处名 / 来源类型 / 完整可点击 URL / 引用位置)、原文摘录加引号标"原文"否则标"转述"、配一条质疑词反查、抓不到就如实写"未能获取"而不许编造;
|
|
245
317
|
- **该渠道的具体抓取手段**(如"Reddit 走 `.json` 端点""视频站走字幕/弹幕工具""X 走 syndication 接口"),避免子代理在登录墙上空转。
|
|
318
|
+
- **「引文净化」约定必须写进派发 prompt**(见下节「回报的引文净化」):子代理的最终回报会经过内容审核,逐字复述辱称或族群贬损文本可能让**整条回报被丢弃**,那一路渠道的证据就全丢了。
|
|
319
|
+
|
|
320
|
+
### 回报的引文净化
|
|
321
|
+
|
|
322
|
+
极端题材(族群冲突、辱骂、暴力内容)里,逐字引文既有**失真风险**(转述链上被裁剪成更冒犯的版本)也有**丢回报风险**。回报时统一按这两档处理:
|
|
323
|
+
|
|
324
|
+
- **事实性表述照常逐字引**——时间、账号名、tweet_id、互动量、可观察行为特征(建号时间、发帖节奏、是否模板化),以及任何不含贬损的中性陈述;
|
|
325
|
+
- **贬损性 / 辱骂性原文不逐字复述**——改为**分类描述 + 定位信息**:`该帖含针对特定族群的贬损表述`(或"人身侮辱""辱华/辱土"这类中性的性质标签)+ **原帖 URL + tweet_id + 发布时间**。需要逐字文本时由主对话自己调 syndication / oembed 接口取,不经子代理回报。
|
|
326
|
+
|
|
327
|
+
**这是「原文摘录加引号并注明"原文"」规则在极端题材上的例外**:不引脏文本,但替代它的定位信息必须齐全,否则等于没给证据。这也不是软化结论——**性质、来源、定位信息一个不少**,少的是可被断章引用的原始脏文本;而"存在辱骂"这一事实本身,分类描述 + 可点击 URL 已经足够,且更经得起复核。极端题材建议按渠道数**多派一路冗余**(3→4):某条回报若被整条丢弃,证据不至于全失。
|
|
246
328
|
|
|
247
|
-
**回报**:每个子代理回报时须标注**来源同源性**(如"本渠道 6 条结果均转载自同一篇首发"
|
|
329
|
+
**回报**:每个子代理回报时须标注**来源同源性**(如"本渠道 6 条结果均转载自同一篇首发"),主对话才能正确计算独立源头数。回报**第一行写渠道状态**——`渠道状态:已取证 / 无命中 / 抓取失败`——主对话才能区分「这条渠道确实没有证据」与「这条渠道的回报丢了」,不至于把后者当成前者直接降档。**回报结构统一**:
|
|
248
330
|
|
|
249
331
|
```
|
|
250
332
|
渠道 → 命中来源清单(带四要素)→ 与主线是否一致 / 矛盾 → 抓取失败的渠道及原因
|
|
@@ -264,6 +346,7 @@ description: 事实核查与资料搜索。当用户要求核实事实/传闻/
|
|
|
264
346
|
- **环境相关的值只放 `tools/local.json`**(模板 `tools/local.example.json`):密钥、端点、state 目录、数据表里的 `${占位符}`,以及可选的能力绑定 `capabilities`、输出约定 `outputConvention`、运行时基线 `runtimeNotes`。代码与数据表**不写死任何主机路径**,`selftest` 里有断言在守这条。
|
|
265
347
|
- **不要在本技能正文里写入任何主机、内网地址、路径或密钥**。本机事实要么进 `local.json`,要么作为"在某环境测得"的证据进 `MEASUREMENTS.md`。
|
|
266
348
|
- **版本纪律**:凡是改动面向使用者的行为(流程、报告模板、判据、触发词),就升 frontmatter 的 `version` 并在 `CHANGELOG.md` 记一条净变化;只改措辞或文档不算。
|
|
349
|
+
- **「利益相关与污染面」是标注制,不是降权制**:不要把任何"利益相关 / 疑似投毒 ⇒ 降档"的规则接进定档。至少会同时坏三件事(非单调、奖励信息垄断、全局降档),三条理由是那一节的正文,改之前先重读。
|
|
267
350
|
- 改文件前先备份;改完跑:`node tools/smoke-plugin.mjs`(插件挂载与单一真相源)、`node tools/doctor.mjs`(需要时加 `--net`)、`node tools/jev-verdict.mjs selftest`、`node tools/route.mjs selftest`、以及受影响的 `regress`。改了本文件还要重跑 `node tools/make-instructions.mjs` 同步 `INSTRUCTIONS.md`(它是生成物)。
|
|
268
351
|
|
|
269
352
|
## 使用边界
|
package/cases/README.md
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
| `dispatch-blind-neutral.json` | 40 | —(仅 id + 任务描述,无标签) | 派发决策的**输入** |
|
|
36
36
|
| `dispatch-label-L1-neutral.json` / `-L2-neutral.json` | 40×2 | 两名独立盲标注员 | 两人一致 35/40 = **87.5%**;不一致的 5 条即"口径本身有歧义" |
|
|
37
37
|
| `dispatch-label-LLM-neutral.json` | 40 | 一个 LLM 用同一份判据作答 | 作为"派发决策让 LLM 现判"的对照臂 |
|
|
38
|
-
| `route-cases-neutral.json` |
|
|
38
|
+
| `route-cases-neutral.json` | 30 | 任务描述 → 期望命中的域 / 路线(按路由表机械裁定) | **30/30**(`route.mjs regress`,0 成本、不调模型、不出网) |
|
|
39
39
|
|
|
40
40
|
前六套语料打的是**判据层**(`jev-verdict.mjs`,要密钥、有成本);最后一套打的是**路由层**(`route.mjs`,纯数据表、0 成本)。路由层同样属于"判据":**改触发词表或域路由表 = 重新校准事件**,必须重跑 `route.mjs regress` 与 `route.mjs selftest`。
|
|
41
41
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_about": "路由层回归语料(不调模型、不出网、0 成本)。每条给一个任务描述与若干 expect* 断言,检查 route.mjs 的确定性路由是否命中该命中的域、避开不该命中的域。跑法:node tools/route.mjs regress --file cases/route-cases-neutral.json",
|
|
3
|
-
"_generated_by": "2026-09-21 新增(补上游只有 selftest 断言、没有独立路由语料的缺口;触发词一改就必须重跑这里);1.3.0 起随七个新域扩到 26
|
|
3
|
+
"_generated_by": "2026-09-21 新增(补上游只有 selftest 断言、没有独立路由语料的缺口;触发词一改就必须重跑这里);1.3.0 起随七个新域扩到 26 例;1.5.1 修兜底域后扩到 30 例(R10 改判 general_fact,新增 R27–R30)",
|
|
4
4
|
"_notes": [
|
|
5
5
|
"域是并列累积的:一个任务可以同时命中多个域,expectDomains 只要求包含(子集检查),不要求独占",
|
|
6
|
-
"expectClosed / expectDispatch 对应 plan 输出的 closedEcosystem / dispatchHint",
|
|
6
|
+
"expectClosed / expectFallback / expectDispatch 对应 plan 输出的 closedEcosystem / fallback / dispatchHint",
|
|
7
7
|
"触发词表属于「判据」的一部分:改动触发词 = 重新校准事件,必须重跑本语料并记录",
|
|
8
|
-
"R15 起覆盖 1.3.0 新增的七个域(司法 / 灾害 / 食安 / 科学常识 / 教育考试 / 体育 / 娱乐),并检查相邻域不串味"
|
|
8
|
+
"R15 起覆盖 1.3.0 新增的七个域(司法 / 灾害 / 食安 / 科学常识 / 教育考试 / 体育 / 娱乐),并检查相邻域不串味",
|
|
9
|
+
"R10 / R27 断言未识别任务落到通用兜底域 general_fact 而不是软件发布域 tech_release;R28 / R29 覆盖 X 平台 / 推特上的骂战与对线(识别社媒域 + 封闭生态);R30 覆盖外方国名进国际域"
|
|
9
10
|
],
|
|
10
11
|
"cases": [
|
|
11
12
|
{
|
|
@@ -63,7 +64,9 @@
|
|
|
63
64
|
{
|
|
64
65
|
"id": "R10",
|
|
65
66
|
"task": "???",
|
|
66
|
-
"expectDomains": ["
|
|
67
|
+
"expectDomains": ["general_fact"],
|
|
68
|
+
"expectNotDomains": ["tech_release"],
|
|
69
|
+
"expectFallback": true
|
|
67
70
|
},
|
|
68
71
|
{
|
|
69
72
|
"id": "R11",
|
|
@@ -159,6 +162,31 @@
|
|
|
159
162
|
"task": "某球员转会费创纪录,核实金额是否属实",
|
|
160
163
|
"expectDomains": ["sports"],
|
|
161
164
|
"expectNotDomains": ["finance"]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"id": "R27",
|
|
168
|
+
"task": "今天天气不错",
|
|
169
|
+
"expectDomains": ["general_fact"],
|
|
170
|
+
"expectNotDomains": ["tech_release"],
|
|
171
|
+
"expectFallback": true
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "R28",
|
|
175
|
+
"task": "确认这几天 X 平台上两国网民骂战的来龙去脉和目前的状况",
|
|
176
|
+
"expectDomains": ["cn_social_rumor"],
|
|
177
|
+
"expectClosed": true,
|
|
178
|
+
"expectFallback": false
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"id": "R29",
|
|
182
|
+
"task": "这几天推特上双方网友对线的来龙去脉",
|
|
183
|
+
"expectDomains": ["cn_social_rumor"],
|
|
184
|
+
"expectClosed": true
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"id": "R30",
|
|
188
|
+
"task": "核查土耳其与某国之间的网络冲突",
|
|
189
|
+
"expectDomains": ["international"]
|
|
162
190
|
}
|
|
163
191
|
]
|
|
164
192
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-fact-check",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Fact-checking skill for DeepSeek Harness: verifies claims against the open web instead of model memory, cross-checks independent sources across domestic and international search ecosystems, and can route three factual judgements (does the evidence support the claim / is this source primary / does this page carry usable text) to a TypeSafe Jev (System One) decision model when a key is configured, falling back to the skill's deterministic rules when it is not.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
package/tools/route.mjs
CHANGED
|
@@ -86,8 +86,8 @@ const DOMAIN_SIGNALS = [
|
|
|
86
86
|
['entertainment_celebrity', /(明星|艺人|演员|歌手|导演|主持人|网红|名人|公众人物|工作室|经纪公司|娱乐公司|粉丝|饭圈|塌房|绯闻|恋情|出道|退圈|封杀|演唱会|影视剧|综艺)/i],
|
|
87
87
|
['cn_policy', /(政策|法规|条例|法条|司法解释|统计年鉴|文号|国务院|征求意见)/i],
|
|
88
88
|
['finance', /(上市|股价|财报|融资|重组|证券|交易所|IPO|币|加密货币|跑路)/i],
|
|
89
|
-
['cn_social_rumor', /(传闻|谣言|辟谣|网传|社媒|公众号|知乎|B\s?站|微博|小红书|抖音|舆情|热搜|大V
|
|
90
|
-
['international', /(
|
|
89
|
+
['cn_social_rumor', /(传闻|谣言|辟谣|网传|社媒|公众号|知乎|B\s?站|微博|小红书|抖音|舆情|热搜|大V|博主|网暴|舆论危机|推特|Twitter|X\s*平台|骂战|对线|论战|口水战|开撕|网络战)/i],
|
|
90
|
+
['international', /(国际|境外|外国|跨国|海外|联合国|世卫|欧盟|美国|美方|日本|日方|欧洲|白宫|国会|当地|土耳其|希腊|俄罗斯|越南|印度|韩国|朝鲜|以色列|巴勒斯坦|乌克兰|阿根廷|巴西|墨西哥|沙特|埃及)/i],
|
|
91
91
|
['company_claim', /(公司|企业|厂商|宣布|合作|行业第一|市占|官网)/i],
|
|
92
92
|
['tech_release', /(版本|更新|发布|仓库|插件|npm|pip|库|许可|LICENSE|CVE|RFC|API|模型|部署)/i],
|
|
93
93
|
]
|
|
@@ -115,14 +115,20 @@ const DOMAIN_ROUTES = {
|
|
|
115
115
|
education_exam: ['gov_notice', 'general_web', 'news_rss'],
|
|
116
116
|
sports: ['sports_official', 'general_web', 'closed_intl_social'],
|
|
117
117
|
entertainment_celebrity: ['entertainment_official', 'closed_cn_social', 'archive'],
|
|
118
|
+
general_fact: ['general_web', 'searxng_meta', 'news_rss', 'archive'],
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
export function planFor(task) {
|
|
121
122
|
const matched = []
|
|
122
123
|
for (const [domain, re] of DOMAIN_SIGNALS) if (re.test(task)) matched.push(domain)
|
|
123
|
-
// An unmatched task falls back to
|
|
124
|
-
//
|
|
125
|
-
|
|
124
|
+
// An unmatched task falls back to the general fact-check domain: a ladder that
|
|
125
|
+
// applies to any topic (party's own release → wire service → metasearch → archive
|
|
126
|
+
// → local media), not the software-release ladder. Falling back to tech_release
|
|
127
|
+
// handed unrelated tasks a README/CHANGELOG ladder, and because that domain is
|
|
128
|
+
// not closed, a hint saying a single route was enough — which talked the agent
|
|
129
|
+
// out of dispatching.
|
|
130
|
+
const fallback = matched.length === 0
|
|
131
|
+
const chosen = fallback ? ['general_fact'] : matched
|
|
126
132
|
const ladders = chosen.map((d) => ({ domain: d, label: matrix.domains[d].label, ladder: matrix.domains[d].ladder }))
|
|
127
133
|
const routeIds = [...new Set(chosen.flatMap((d) => DOMAIN_ROUTES[d] || []))]
|
|
128
134
|
const chosenRoutes = routeIds.map((id) => routes.routes.find((r) => r.id === id)).filter(Boolean)
|
|
@@ -131,15 +137,20 @@ export function planFor(task) {
|
|
|
131
137
|
return {
|
|
132
138
|
task,
|
|
133
139
|
domains: chosen,
|
|
140
|
+
// True when no domain matched and the general ladder was used: read that ladder
|
|
141
|
+
// as a starting point, not as a domain verdict.
|
|
142
|
+
fallback,
|
|
134
143
|
closedEcosystem: closed,
|
|
135
144
|
factPointsInText: factPoints,
|
|
136
145
|
ladders: substDeep(ladders),
|
|
137
146
|
routes: chosenRoutes.map((r) => ({ id: r.id, when: subst(r.when), primary: substDeep(r.primary), notes: subst(r.notes) })),
|
|
138
147
|
failureActions: substDeep(routes._failure_actions),
|
|
139
148
|
localPlaceholdersUnset: unresolved(),
|
|
140
|
-
dispatchHint:
|
|
141
|
-
? '
|
|
142
|
-
:
|
|
149
|
+
dispatchHint: fallback
|
|
150
|
+
? '未识别事实类型(兜底域)→ 按 SKILL.md 的信号表判断:涉及封闭生态 / 需抓大量长文 / 事实点 ≥4,任一命中即派子代理'
|
|
151
|
+
: closed || chosen.length >= 3 || factPoints >= 4
|
|
152
|
+
? '需要多路取证(封闭生态 / 多类型事实点)→ 候选派子代理;最终仍以派发判据标注集为准'
|
|
153
|
+
: '单路可覆盖,串行处理即可',
|
|
143
154
|
}
|
|
144
155
|
}
|
|
145
156
|
|
|
@@ -248,7 +259,23 @@ function selftest() {
|
|
|
248
259
|
const s = JSON.stringify(routes._failure_actions)
|
|
249
260
|
return s.includes('403') && (s.includes('超时') || s.includes('000'))
|
|
250
261
|
})
|
|
251
|
-
t('未匹配任务有兜底域', () => planFor('???').domains[0] === '
|
|
262
|
+
t('未匹配任务有兜底域', () => planFor('???').domains[0] === 'general_fact')
|
|
263
|
+
t('兜底域不是软件发布域(那套阶梯与多数任务无关)', () => planFor('???').domains[0] !== 'tech_release')
|
|
264
|
+
t('兜底域给出通用来源阶梯', () => {
|
|
265
|
+
const l = planFor('今天天气不错').ladders[0].ladder.join('|')
|
|
266
|
+
return l.includes('通讯社') && l.includes('当事方')
|
|
267
|
+
})
|
|
268
|
+
t('兜底任务提示按信号表判断派发(不误劝退)', () => {
|
|
269
|
+
const h = planFor('???').dispatchHint
|
|
270
|
+
return h.includes('未识别事实类型') && h.includes('派子代理')
|
|
271
|
+
})
|
|
272
|
+
t('兜底任务显式标记 fallback', () => planFor('???').fallback === true && planFor('网传某地发生地震').fallback === false)
|
|
273
|
+
t('社交平台战类任务识别出封闭生态', () =>
|
|
274
|
+
planFor('确认这几天 X 平台上两国网民骂战的来龙去脉和目前的状况').closedEcosystem === true)
|
|
275
|
+
t('社交平台战类任务识别为社媒域', () =>
|
|
276
|
+
planFor('这几天推特上双方网友对线的来龙去脉').domains.includes('cn_social_rumor'))
|
|
277
|
+
t('常见外方国名识别为国际域', () =>
|
|
278
|
+
planFor('核查土耳其与某国之间的网络冲突').domains.includes('international'))
|
|
252
279
|
t('常见任务的路线数不超过 5 条', () => planFor('核查某公司宣称的合作是否属实,需要境外监管文件').routes.length <= 5)
|
|
253
280
|
t('可移植:占位符可由 JEV_* 环境变量解析', () => {
|
|
254
281
|
const old = process.env.JEV_SEARXNG_URL
|
|
@@ -335,6 +362,7 @@ function regress(file, out) {
|
|
|
335
362
|
if (c.expectDomains) checks.push(['expectDomains', c.expectDomains.every((d) => p.domains.includes(d))])
|
|
336
363
|
if (c.expectNotDomains) checks.push(['expectNotDomains', c.expectNotDomains.every((d) => !p.domains.includes(d))])
|
|
337
364
|
if (typeof c.expectClosed === 'boolean') checks.push(['expectClosed', p.closedEcosystem === c.expectClosed])
|
|
365
|
+
if (typeof c.expectFallback === 'boolean') checks.push(['expectFallback', p.fallback === c.expectFallback])
|
|
338
366
|
if (c.expectRoutes) checks.push(['expectRoutes', c.expectRoutes.every((r) => p.routes.some((x) => x.id === r))])
|
|
339
367
|
if (typeof c.expectDispatch === 'boolean') {
|
|
340
368
|
checks.push(['expectDispatch', c.expectDispatch === (p.dispatchHint.startsWith('需要多路取证'))])
|
|
@@ -346,6 +374,7 @@ function regress(file, out) {
|
|
|
346
374
|
passed: ok,
|
|
347
375
|
failed: failedOn,
|
|
348
376
|
domains: p.domains,
|
|
377
|
+
fallback: p.fallback,
|
|
349
378
|
closedEcosystem: p.closedEcosystem,
|
|
350
379
|
routes: p.routes.map((r) => r.id),
|
|
351
380
|
})
|
package/tools/source-matrix.json
CHANGED
|
@@ -106,6 +106,13 @@
|
|
|
106
106
|
"closed": true,
|
|
107
107
|
"note": "工作室声明是当事人立场而非中立证据:写进报告时须标注为「当事人声明」,不可当作第三方证据",
|
|
108
108
|
"languages": ["zh", "en"]
|
|
109
|
+
},
|
|
110
|
+
"general_fact": {
|
|
111
|
+
"label": "通用事实核查(事实类型未识别时的兜底域)",
|
|
112
|
+
"ladder": ["当事方或主管机构的原始发布(官网、公告、原始账号)", "通讯社与官方广播(中外各一组)", "自托管元搜索与批量搜索交叉", "存档快照(Wayback)核对页面是否存在、是否被改", "当事国本地媒体(当地语言原文)", "社区与个人讨论(仅线索)"],
|
|
113
|
+
"closed": false,
|
|
114
|
+
"note": "兜底域:任务文本匹配不到任何具体事实类别时使用。早期版本兜底到 tech_release,那条阶梯是「官方仓库 / 包管理器元数据」,与多数任务无关,会同时给出错误的来源阶梯与错误的派发建议(该域 closed=false,提示会说「单路可覆盖」)。closed=false 只表示「尚未识别出封闭生态」,不表示任务一定不涉及——派发与否仍按 SKILL.md 的信号表判断。",
|
|
115
|
+
"languages": ["zh", "en"]
|
|
109
116
|
}
|
|
110
117
|
},
|
|
111
118
|
"_rules": [
|