Skip to content

Commit 87a236d

Browse files
committed
Report the swap control, and keep Jev in the experiment
1 parent 5ba9068 commit 87a236d

3 files changed

Lines changed: 211 additions & 119 deletions

File tree

‎bench/confusion.ts‎

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -898,22 +898,40 @@ async function main(argv: string[]): Promise<void> {
898898
)
899899
console.log(`${D(' 配对比较,90% 区间(单侧 α=0.05 ⇒ 等价结论的置信水平是 90%)')}`)
900900
const bad = judged.filter((c) => c.gold === 'bad')
901+
const good = judged.filter((c) => c.gold === 'good')
902+
const pct = (x: number) => `${x >= 0 ? '+' : ''}${(x * 100).toFixed(1)}%`
903+
console.log(`${D(' ① 拦住坏东西的能力差(正 = 闸门比「没有闸门」抓得多)')}`)
901904
for (const arm of ARMS) {
902905
if (arm === 'accept-all') continue
903-
// 假确认那一侧:只在「该拦」的格子上比(接受了就是假确认)
904-
const b1 = bad.filter((c) => c.verdicts[arm] === 'accept' && c.verdicts['accept-all'] !== 'accept').length
905-
const c1 = bad.filter((c) => c.verdicts[arm] !== 'accept' && c.verdicts['accept-all'] === 'accept').length
906-
const t1 = tostPaired(b1, c1, bad.length, MARGIN)
907-
const mde = pairedMde(bad.length, (b1 + c1) / Math.max(1, bad.length))
908-
const pct = (x: number) => `${x >= 0 ? '+' : ''}${(x * 100).toFixed(1)}%`
906+
// 捕获那一侧:只在「该拦」的格子上比。正负号翻过来,让「正数 = 更好」符合直觉
907+
const b = bad.filter((c) => c.verdicts[arm] !== 'accept' && c.verdicts['accept-all'] === 'accept').length
908+
const c = bad.filter((c) => c.verdicts[arm] === 'accept' && c.verdicts['accept-all'] !== 'accept').length
909+
const t = tostPaired(b, c, bad.length, MARGIN)
910+
const mde = pairedMde(bad.length, (b + c) / Math.max(1, bad.length))
909911
console.log(
910-
` ${arm.padEnd(12)}假确认差 ${pct(t1.delta).padStart(7)} 90%区间 [${pct(t1.lower)}, ${pct(t1.upper)}] ` +
911-
`p=${t1.p.toFixed(3)} ${t1.equivalent ? G('✓ 可声称等价') : D('不足以声称等价')}` +
912-
`${D(` 本次设计对假确认的 MDE ≈ ${(mde * 100).toFixed(1)} 个百分点(n=${bad.length})`)}`,
912+
` ${arm.padEnd(12)}${pct(t.delta).padStart(7)} 90%区间 [${pct(t.lower)}, ${pct(t.upper)}] ` +
913+
`p=${t.p.toFixed(3)} ${t.equivalent ? G('✓ 可声称等价') : D('不足以声称等价')}` +
914+
`${D(` MDE ≈ ${(mde * 100).toFixed(1)} 个百分点(n=${bad.length} 个该拦的)`)}`,
915+
)
916+
}
917+
console.log(`${D(' ② 误伤好活的程度(正 = 闸门比「没有闸门」更容易拦下合法的活)')}`)
918+
for (const arm of ARMS) {
919+
if (arm === 'accept-all') continue
920+
// 假警报那一侧:只在「该放行」的格子上比
921+
const b = good.filter((c) => c.verdicts[arm] !== 'accept' && c.verdicts['accept-all'] === 'accept').length
922+
const c = good.filter((c) => c.verdicts[arm] === 'accept' && c.verdicts['accept-all'] !== 'accept').length
923+
const t = tostPaired(b, c, good.length, MARGIN)
924+
const mde = pairedMde(good.length, (b + c) / Math.max(1, good.length))
925+
console.log(
926+
` ${arm.padEnd(12)}${pct(t.delta).padStart(7)} 90%区间 [${pct(t.lower)}, ${pct(t.upper)}] ` +
927+
`p=${t.p.toFixed(3)} ${t.equivalent ? G('✓ 可声称等价(误伤可忽略)') : D('不足以声称等价')}` +
928+
`${D(` MDE ≈ ${(mde * 100).toFixed(1)} 个百分点(n=${good.length} 个该放行的)`)}`,
913929
)
914930
}
915931
console.log(
916-
`${D(' ★ 阴性结论必须带 MDE:说「测不出来」时,同一行要写清这套设计本来能看见多大差异')}`,
932+
`${D(' ★ 阴性结论必须带 MDE:说「测不出来」时,同一行要写清这套设计本来能看见多大差异。')}` +
933+
`\n${D(' ★ 这个工具真正的用武之地是「两组本来就没差别」的那些比较(如 Round 1 的契约 vs if/else),')}` +
934+
`\n${D(' 它在那里才能把「测不出来」写成正面结论;在本文这批数据上各组是真有差别的。')}`,
917935
)
918936

919937
// ── 复合可靠性:不发明 r,报 r* ──────────────────────────

‎docs/EVAL-PLAN-2026-09.md‎

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ n=30 就够;DERAIL 报的是「跑到第一次违规用了多少轮」,上
134134
| A | **混淆矩阵仪表**:把「谁批准了什么」折成 2×2 + c/f/r + 复合可靠性 | `src/verifier-matrix.ts` + `tests/verifier-matrix.test.ts` + `bench/confusion.ts` | ✅ 已落地(见 §5) |
135135
| B | **配对化**:同一批候选跨臂复用 + 精确 McNemar | `bench/confusion.ts` | ✅ 已落地 |
136136
| C | **分母纪律 + Coverage + 零事件上界** | `src/verifier-matrix.ts`(`Proportion` 永远带分子分母) | ✅ 已落地;保守纳入敏感度表未做 |
137-
| D | **等价检验(TOST)** | `src/stats.ts` | ⬜ 未做 —— 这是五篇都没做、我们必须自己发明的那一件 |
137+
| D | **等价检验(TOST)+ 最小可检测差异** | `src/equivalence.ts` + `tests/equivalence.test.ts` | ✅ 已落地(12 个测试,含「差异大时绝不许说等价」的反例);Δ 仍需 owner 定 |
138138
| E | **做大效应**:伪证据任务改成 40–80% 假成功量级 | `bench/claim-variants.ts` 的任务表 | ⬜ 未做 |
139-
| F | **控制臂** | `bench/confusion.ts` | 🟡 ①有效前提负控 + ②证伪操纵已落地;②**判据未满足**且操纵本身有混淆,见 §5.3 |
139+
| F | **控制臂** | `bench/confusion.ts` | ✅ ①有效前提负控 + ②证伪操纵(**换成别的任务的证据**)。②给出了决定性结果:同族判官的裁决对证据内容**完全不敏感** |
140140

141141
**A、B、C 必须先做**(已完成)—— 旧的端到端结果(1 个事件、臂间漂移)既欠功效也不可解释。
142142

@@ -216,3 +216,41 @@ npm run claim-confusion [--repeat N] [--limit N]
216216

217217
⇒ 下一步要做的是**长度相当、非空、不矛盾**的填充格(filler),在那之前两边都不下结论。
218218
这条记在案,不许拿它当「判官不读证据」的证据用。
219+
220+
### 5.4 证伪操纵的最终形态与结果(2026-09)
221+
222+
**做对这件事踩了两次坑,两次都会得出错误结论:**
223+
224+
1. **抹掉证据格** —— 第一次的形态。结果无法解释:空格子**本身就是信号**
225+
(「什么都没记录」),照着空格子答 `unsupported` 仍然是在读帧。判据没满足,
226+
按失败报。
227+
2. **换成同一个任务、另一次重复的证据** —— 第二次的形态。结果**一格都没变**,
228+
看起来像「判官不读证据」。真实原因:动作是照 `task.required` 脚本化走的,
229+
同一任务的每次重复读的是同一批文件,**渲染出来的证据几乎是同一个字符串**。
230+
换了个寂寞。
231+
3. **换成别的任务、金标「该放行」那一格的证据**(最终形态)—— 真实、非空、
232+
形态相同、内容无关。
233+
234+
最终结果(n=72):
235+
236+
| 臂 | 换证据后变了几格 | 假警报 真帧 → 换证据 |
237+
|---|---|---|
238+
| **`judge-jev`** | **37 / 72** | **5% → 65%** |
239+
| `judge-same`(同族通用模型) | **0 / 72** | 7% → 7% |
240+
| `compiled` | 2 / 72 | 2% → 5% |
241+
242+
★ **一句话结论:Jev 的裁决依赖声明过的那份帧;把同一个模型配上提示词当判官,
243+
它根本不看证据格。** 这一条重排了整张表 —— `judge-same` 抓得少不是「模型不会判」,
244+
而是**证据格对它来说是装饰**。
245+
246+
### 5.5 三次同配置运行的排序不稳定(必须写进论文)
247+
248+
| 运行 | 误导候补 | `judge-jev` 捕获 | `judge-same` 捕获 | McNemar |
249+
|---|---|---|---|---|
250+
| 1 | 9 | 44% | 56% | 不可分辨 |
251+
| 2 | 11 | 73% | 36% | p = 0.063 |
252+
| 3 | 12 | 82% | 8% | **p = 0.006** |
253+
254+
**方向翻过一次。** 十来个正例不足以给两个闸门排序,run-to-run 的波动比要测的差异还大。
255+
能稳定复现的只有操纵那一条。⇒ 论文里要写成「机制已确立、效应量未确立」,
256+
并附上 MDE(12 个正例时约 23 个百分点,300 个时约 5 个百分点)。

0 commit comments

Comments
 (0)