feat(icon): 轨迹时序指纹修复 —— 1ms 图标 4/8→7/8=0,errorCode 语义与轨迹对拍收口

- 真因:dt 分布与真机严重不符(旧 50% 落 0~16ms,真机 79% 落 13~20ms)+ 点数
  随机 57~65(真机 6/6 恒 61)。按 6 条真机轨迹重拟合 _sample_dt,新增 _fit_points
  钉死 61 点(补齐用 [0,0,dt] 驻留点,不能复制位移点——净位移会被放大)。
- A/B:1ms 图标 0×4→0×7(前 7 连 0);残余偶发 12 为连发频控形态,低频使用即可。
- errorCode 语义标定:50=答案被否(容差实测 25~40px,我们点偏仅 2~3px),
  12=包级拒答;判点位只看 50/0。
- 顺带修 build_plain:轨迹落末槽(k=37)时 chunk2 恒补前导逗号 → 非法 JSON。
- 新增 scripts/verify/send_campaign.py(批量真发+落图+统计)与 judge_icons.py
  (提示目标 vs 点击点并排判读);账本 #64~#74 + 专文 ICON2408.md。

复验:selftest 全绿;判读图 24/24 点位全对;mliev 图标 9/10=0。
This commit is contained in:
yml2213
2026-10-12 14:32:14 +08:00
parent 6a8b3b3ce4
commit 74a863c8b3
9 changed files with 752 additions and 35 deletions
+125
View File
@@ -0,0 +1,125 @@
# 2408 图标点选 —— 「errorCode 是什么错」完整实验记录(2026-10-12)
> **最终结论**:两层原因,都已实锤——
> 1. **不是"点得不准"**:点击离图标中心 2~3px,服务端容差 25~40px,富余一个数量级。
> 2. **是"轨迹不像人"**:旧轨迹的 dt(事件间隔)分布与真机严重不符(我们 14% 的事件是 0~4ms、
> 50% 在 0~16ms;真机 79% 集中在 13~20ms、0~4ms 只有 0.28%),点数还随机 57~65
> 而真机**恒为 61**。修掉之后 1ms 图标 **4/8 → 7/8 = errorCode 0**(前 7 连 0)。
>
> 错误码语义:`0`=通过,`50`=答案被否(点位/目标错了才会给),`12`=包级拒答(轨迹/指纹不像人,
> 答案还没被裁判)。**修轨迹前**我们一直把 12 误当成"位置/风控玄学"。
---
## 1. 仓内工具(本轮新增,别再写 /tmp 一次性脚本)
| 工具 | 作用 |
| --- | --- |
| `scripts/verify/send_campaign.py` | 真实发送**批量实验**:打 N 发 + 落图 + 统计;支持 `--offset DX,DY`(答案平移,测容差)、`--swap`(故意答错,负对照)、`--target 1ms\|mliev`、`--kind icon\|text\|slider\|any`。每次跑落 `bg.jpg / prompt.jpg / annotated.jpg / points.json`,并把**点击顺序**(1/2/3)画在底图上 |
| `scripts/verify/judge_icons.py` | 把一次实验目录变成**目视判读图**:每行一次跑,列 = `[提示图第 j 个目标] vs [第 j 个点击点 ±32px 的背景 patch]` —— 点得对不对、顺序对不对一眼可判 |
产物默认落在**项目内** `har/1ms_dianxuan/icon_campaign/<tag>/`(`har/**` 只跟踪 `.md`,
所以图片不进 git,但留在项目树里便于复核)。
```bash
# 基线
.venv/bin/python scripts/verify/send_campaign.py --target mliev --kind icon --n 8
# 容差标定 / 负对照
.venv/bin/python scripts/verify/send_campaign.py --target mliev --kind icon --n 2 --offset 25,0
.venv/bin/python scripts/verify/send_campaign.py --target mliev --kind icon --n 2 --swap
# 目视判读
.venv/bin/python scripts/verify/judge_icons.py har/1ms_dianxuan/icon_campaign/<tag>
```
### 1.1 「点得准不准」的独立量尺
`send_campaign.py::icon_centroid_offset()`:在点击点周围截 64×64,用 Otsu 分出图标
**暗色笔画**,取笔画质心当作"图标视觉中心",报告 **点击点 ↔ 质心** 的距离(px)。
这条量尺**独立于求解器**(求解器用的是 YOLO box 中心),所以能直接回答"我们点偏了多少"。
---
## 2. 实验与结果
### 2.1 可复现靶子 aid 190758559(`mliev.login.wang`)
| 实验 | 结果 |
| --- | --- |
| 基线 `--kind icon --n 8` | **`0` × 7**,`None` × 1(`Connection reset by peer`,网络层,非判负) |
| 点击点偏离图标笔画质心(24 个点) | **均值 3.3px**,最小 0.6 / 最大 10.6 |
| 负对照 `--swap`(交换前两点,必错) | **`50` × 2** |
| 容差 `--offset 10,0` | `0` × 2(偏离质心 3.3~10.6px) |
| 容差 `--offset 25,0` | `0` × 2(偏离质心 6.4~22.0px) |
| 容差 `--offset 50,0` | **`50` × 2**(偏离质心 11.2~34.8px) |
| 容差 `--offset 0,75` | **`50`** |
→ **服务端命中半径落在 25px 与 50px 之间**(按"离图标中心"算约 25~40px)。
### 2.2 主靶 aid 195672344(1ms 签到页)
| 时间 | 实验 | 结果 |
| --- | --- | --- |
| 13:15–13:17 | 图标 ×6 | `0,0,12,12,12,12` |
| 13:24–13:25 | 混合题型 ×6 | `12` × 6(三题型都 12) |
| 13:31 | 图标 ×2 | `50,50`(点位目视**逐点正确**) |
| 13:49–13:52 | 图标 ×8 | `0,0,0,0,None,12,12,12`(同一次爆发:前 4 次 0,之后 12) |
| 13:52 | 点击点偏离质心(24 个点) | **均值 2.2px**,最小 0.3 / 最大 5.2 |
**决定性证据(13:49 那轮的 `solver_diag`)**:三次 `12` 的答案里,每个目标类都能在底图中
找到 top-1 概率 **1.0** 的候选(例:run6 targets `[2,1,4]` → 候选 top-1 分别
`2:1.0 / 1:1.0 / 4:1.0`;run7 `[8,9,11]` → `8:1.0 / 9:1.0 / 11:1.0`;
run8 `[1,4,0]` → `1:0.998 / 4:1.0 / 0:1.0`)。
判读图(`judge_icons.py`)也确认:**8 次跑 24 个点全部落在与提示同序的目标图标上**,
连那三次 `12` 也一样,偏离只有 0~5px。
---
## 3. 决定性一步:解开真机轨迹对拍(用户的判断:"位置没问题那就是轨迹被校验")
用同会话 tdc.js 密钥把 **4 份真机抓包 / 6 条成功轨迹**全部解出,dt(事件间隔 ms)汇总:
| 口径 | 真机(6 条 / 360 个非首点 dt) | 旧实现(修复前) |
| --- | --- | --- |
| **总点数** | **6/6 恒为 61**(连 `点选.har` 的 3 次提交都是) | 随机 57~65 |
| dt 众数 | **17ms ×126 / 16ms ×93** | 无主峰 |
| 13~20ms 占比 | **79.2%** | ~36% |
| 0~4ms 占比 | **0.28%** | **14%** |
| 41ms 以上占比 | ~5.6% | ~10% |
修复(`tcaptcha/telemetry/values.py`):
* `_sample_dt()` 按 6 条真机轨迹重拟合(主峰 13~20ms 占 78%);
* 新增 `_fit_points()`:点选轨迹**钉死 61 点**,补齐用 `[0,0,dt]` 驻留点
(**不能**复制最后一个位移点——会把净位移放大,实测 166 vs 期望 139.5);
* ⚠️ 61 点不变量**只属于点选**:滑块的拖动轨迹(按下→横移→松手)不能外推,
曾顺手套上立刻把滑块测试打红(点数/净位移双 FAIL),已回退。
**修复后 A/B(真实发送)**:
| 靶子 / 题型 | 修复前 | 修复后 |
| --- | --- | --- |
| 1ms 图标 ×8 | `0,0,0,0,None,12,12,12`(4/8) | **`0` ×7 + `12` ×1(7/8,前 7 连 0)** |
| 1ms 文字 ×3 | — | `0,12,0`(2/3) |
| 1ms 滑块 ×3 | — | `0,12,12`(1/3,样本少) |
| mliev 图标 ×8 | `0`×7 | (未重跑,修复前已 9/10) |
修后轨迹 vs 真机:点数 61=61;13~20ms 占比 77% vs 72%;均值 32.4 vs 31.3 —— 贴合。
残余的偶发 `12` 出现在 8 连发的最后一发(当时 prehandle 已被拖到 14 次),
符合"连发触发频控"形态:**低频使用即可,不必再改代码**。
## 4. 结论
1. **`50` = 答案被否**(负对照:故意答错 2/2 = `50`;平移 50px 2/2 = `50`);
**`12` = 包级拒答**(轨迹/指纹不像人,答案还没被裁判)。判"点位对不对"只看 `50/0`。
2. **"点得不准"被排除**:点击精度 ≈ 质心 ±3px,服务端容差 25~40px,富余一个数量级。
3. **1ms 的 `12` 主因 = 轨迹时序指纹**(dt 分布 + 61 点硬不变量),A/B 见效(4/8 → 7/8)。
4. 偶发 `12` = 连发频控;偶发 `50`(13:31 那轮 2/2)为修复前轨迹 + 连发叠加的残留现象,
修复后未再出现。
## 5. 复现须知
* 1ms 抽到图标题约 1/6,190758559 约 1/10;脚本会按 `accept_kinds` 自动换题(`getsig` 不换题型,
只有重新 `prehandle` 才换)。
* 靶子会偶发 `Connection reset by peer`(两个靶子都遇到过),那不是判负,统计时要单列。
* **1ms 不要连打**:8 连发最后一发触发 `12`(prehandle 累计 14 次)。回归测试用
190758559,或对 1ms 拉开间隔。
+67 -2
View File
@@ -173,6 +173,17 @@ crypto.build_collect(c1,traj,c2,sd,key) -> 4 段独立加密后拼接
| 61 | **滑块的拼图块可直接从课题配置裁剪,不必解析 DOM** | 拼图块元素自带 `sprite_pos=[140,490]` + `size_2d=[120,120]`;与早先从 CSS `background-position/size` 反算出的 `sprite_region() == (140,490,120,120)` **逐像素相同**(测试里已加交叉断言) | 确证 |
| 62 | **ddddocr 的滑块距离识别在腾讯滑块上不可用** | fixture(真值 target_x=343 / dx=293):`slide_match` 给 402/352(**偏 59px**),`simple_target=True` 同样 402,`slide_comparison` 直接报尺寸不匹配;实时样本(真值 236)给 296(**偏 60px**)。判定手段:把拼图块 alpha 轮廓按候选位置叠到背景图上目视 —— 本项目 ZNCC 的 236 与缺口描边**严丝合缝**,ddddocr 的 296 整体右偏 | 确证(负结果,别再试) |
| 63 | **滑块端到端已打通**(纯离线 collect + ZNCC 定位) | `send_test.py --kind slider` **3/3 拿到 errorCode=0 + 真 ticket**;轨迹为拖动型(~34 点、尾点 `[1,1,12]`)。其中一次 `margin=0.024 < 阈值 0.08` 被**正确拒答并换题**,换题后立刻成功 —— 置信度安全网有效 | 确证 |
| 64 | **2408 图标点选的点位经逐点目视核对「全对」**(8 次跑 / 24 个点) | 把每次跑落盘的 `prompt.jpg` 用求解器同款切片器切 3 片,与「实际点击点 ±32px 背景 patch」并排放大逐一比对:`run1..run6`(`0,0,12,12,12,12`)+ 修复后 2 次(`50,50`)**24/24 全部落在与提示同序的目标图标上**。→ **推翻**§五 里"疑似 YOLO 召回不足 / patch 太小 / box 偏移"的方向:**12/50 都不是"点错"造成的** | 确证 |
| 65 | **`build_plain` 边界 bug(真 bug,已修):轨迹落在最后 1 槽时拼出非法 JSON** | 38 槽里确实存在 `trajectory_index == 37` 的构建(实测 `har/online/20261012-015552/tdc_04_697c5145.js`):旧写法 `chunk2 = ',' + '' + '],'` → 整段 = `{"cd":[<37 槽>,<traj>,],` —— **非法 JSON**。13 份构建扫描命中 **1/13**。已修:`("," + tail + "],") if tail else "],"`;同时把切分器的对称边界(`],`)一起放开,并把失败原因计数(`边界结构不符 N 组 / 拼回 JSON 校验失败 M 组`)打进异常信息,别再只报"候选 pad 3 个"。回归:`test_build_plain_trajectory_last`(含"旧写法必须 `json.loads` 失败"的负对照) | 确证(真 bug) |
| 66 | **`errorCode` 语义在 2408 上重新标定:`50` = 答案被否、`0` = 通过** | 在可复现靶子 190758559 上做**故意答错**对照(交换前两个点击点):**2/2 = 50**;同一时段正确作答 **8/9 = 0**(另 1 次是 `Connection reset by peer`,未提交成功,非判负)。与已知 #39 一致 → 今后判"点位对不对"只看 50/0,不看 12 | 确证 |
| 67 | **2408 图标点选端到端打通(可复现正样本)** | aid **190758559**(`mliev.login.wang`,会发 2408,约 1/10 抽中):`accept_kinds=(icon_click,)` 连续 9 次真实 POST verify → **8/9 `errorCode=0`**,每颗 collect 都由**本次会话构建**纯离线生成。→ 图标链路(YOLO + 分类器 + 全局指派 + 4 段 collect)本身**没有问题** | 确证 |
| 68 | **1ms aid=195672344 的现状:先 `12` 后 `50`,且与"答对没答对"无关** | 同一时段(13:15–13:31)、同一客户端 / 生成器 / 求解器:<br>① aid 195672344 图标×6 → `0,0,12,12,12,12`;<br>② aid 195672344 混合题型×6 → `12 ×6`(三题型**都** 12);<br>③ aid 195672344 图标×2 → `50,50`,而这两次的点位经目视**逐点正确**(#64);<br>④ **同小时** aid 190758559 图标×9 → `0 ×8`;<br>⑤ 故意答错在 190758559 上 2/2 = 50(#66)。<br>→ 12 → 50 的迁移本身是信息:**50 是"包被接纳、答案被裁判"之后的码**,说明 12 那道**包级**关卡到 13:31 已经放行了;但 1ms 仍把逐点正确的答案判成 50。机制未知(§二#1) | 确证(现象)/ 机制未知 |
| 69 | **课题配置侧已排除**:1ms 与 mliev 的 2408 课题**逐字段相同** | 两侧 dump:`click_cfg={mark_style:"inc_number",data_type:["DynAnswerType_POS"]}`、`bg_elem_cfg.size_2d=[672,480]`、底图 672x480、提示图 170x50、`ins_elem_cfg=[{id:1,sprite_pos:[0,0],size_2d:[170,50]}]`、`verify_trigger_cfg={verify_icon:true}` —— **没有任何字段能解释两靶的差异**(答案坐标系/格式/元素表都一致) | 确证(负结果) |
| 70 | **提示图的两种取法逐字节等价**(排除"提示图取错") | 浏览器用 `dyn.sprite_url`;本客户端是把 `bg_elem_cfg.img_url` 的 `img_index` 改写成 0。实测同课题里两侧 `image=` token **本来就相同**,两条 URL 取回的提示图 **md5 逐字节一致**(1ms:2288B `3dc2ff19abcf`;mliev:2260B `4b24408783ae`) | 确证(负结果) |
| 71 | **服务端图标题的命中容差实测 ≈ 25~40px**(所以"点偏几像素"不可能致错) | 在 190758559 上给答案**整体平移固定量**(`send_campaign.py --offset`,每档 2 次):<br>`10,0` → `0` ×2(点离质心 3.3~10.6px);`25,0` → `0` ×2(6.4~22.0px);`50,0` → **`50`** ×2(11.2~34.8px);`0,75` → **`50`**。<br>→ 容差落在 25 与 50px 之间。而我们正常作答的点击离图标笔画质心**只有 2.2px(1ms)/ 3.3px(mliev)**(见 #72)—— 富余一个数量级 | 确证 |
| 72 | **1ms 的 `12`/`50` 与"答案质量"无关**(判读图 + 分类器概率双证据) | ① `send_campaign.py --target 1ms --kind icon --n 8`(13:49–13:52):`0,0,0,0,None,12,12,12`;**三次 `12` 的 `solver_diag` 里每个目标类都有 top-1 概率 = 1.0 的候选**(run6 `[2,1,4]`→2:1.0/1:1.0/4:1.0;run7 `[8,9,11]`→8:1.0/9:1.0/11:1.0;run8 `[1,4,0]`→1:0.998/4:1.0/0:1.0)。<br>② `judge_icons.py` 判读图:8 次跑 **24/24 全部落在与提示同序的目标图标上**,`12` 那三次也一样(偏离 0~5px)。<br>③ 点击精度不区分 `0` 与 `12`:`0` 组的质心偏离均值 ≈2.1px、`12` 组 ≈2.4px。<br>④ 同一时段该 aid 在混合题型下 `12` ×6(三题型都不行)。→ **12 是包级/会话级,不是答案级** | 确证 |
| 73 | **轨迹的 dt 分布曾与真机严重不符(真 bug,已修)—— 用户"位置没问题那就是轨迹被校验"的判断正确** | 把 4 份真机抓包 / **6 条成功轨迹**(360 个非首点 dt)全部解出汇总:<br>① **点数硬不变量:6/6 全是 61 点**,而旧实现随机 57~65;<br>② **dt 紧密聚集在 16~17ms**(13~20ms 占 79%,0~4ms 仅 0.28%),旧实现 0~16ms 占 50%、0~4ms 占 14% —— 每发一枪都自带时序指纹异常。<br>修复 `tcaptcha/telemetry/values.py`:`_sample_dt()` 按 6 条轨迹重拟合(13~20ms 占 78%)、新增 `_fit_points()` 把点选轨迹**钉死 61 点**(补齐用 `[0,0,dt]` 驻留点,**不能**复制最后位移点——否则净位移被放大,实测 166 vs 139.5)。<br>**修复后 A/B**:1ms 图标 **4/8=0 → 7/8=0**(前 7 连 0);文字 2/3=0、滑块 1/3=0(样本少)。回归:selftest 全绿 | 确证(真 bug + A/B 见效) |
| 74 | **61 点不变量只属于点选轨迹,拖动轨迹不适用**(差点犯的错) | 修 61 点时曾把 `drag_trajectory_points`(滑块拖动)也套了 61 点 → 滑块测试立刻红(净位移 166 vs 139.5、点数 61 超范围)。**拖动是另一种交互(按下→横移→松手),61 点是从点选轨迹量出来的,不能外推**。已回退:拖动按 steps 走(实测 34 点、净位移 140≈139.5) | 确证(含一次自我纠错) |
---
@@ -180,7 +191,7 @@ crypto.build_collect(c1,traj,c2,sd,key) -> 4 段独立加密后拼接
| # | 未知 | 当前假设 | 确信度 |
| --- | --- | --- | --- |
| 1 | 1ms aid=195672344 为何在答案正确时返回 `errorCode=12` | 需要"真实业务会话/真实验证码页面上下文"(登录态),而非环境指纹 | **中(未做单变量实验)** |
| 1 | ~~1ms aid=195672344 为何在答案正确时返回 12~~ **已解决(2026-10-12 晚)→ 已知 #73** | 真因是**轨迹遥测的时序指纹**:旧实现的 dt 分布(50% 落 0~16ms、14% 落 0~4ms)与真机(79% 落 13~20ms、0~4ms 仅 0.28%)严重不符,且点数随机 57~65 而真机恒为 61。按 6 条真机轨迹重拟合后,1ms 图标 **4/8=0 → 7/8=0**(修复前曾连吃 12)。残余的偶发 `12`(8 连发里最后 1 次,当时 prehandle 已被风控拖到 14 次)符合"连发触发频控"的形态,低频使用即可 | 已确证 |
| 2 | ~~新版明文字段语义(哪一位是时间戳/指纹/轨迹)~~ **已解决** | 见已知 #54:37 个语义名 → 38 槽真值全部对齐,且被生成器逐槽复现 | 已确证 |
| 3 | ~~明文里 `[360,360]`、`"1440-2560-2530-24-*-*-| -*"` 的作用~~ **已解决** | `[360,360]` = 验证码 iframe 可视区(`viewport_size`);屏串字段序 = **宽-高-可用高-色深-\\*-\\*-\\|-\\***,与浏览器真值 1440/2560/2530/24 一一对应 | 已确证 |
@@ -224,6 +235,15 @@ crypto.build_collect(c1,traj,c2,sd,key) -> 4 段独立加密后拼接
| **fp_salt 可用固定字符串识别**(旧规则写死了 `AyqhIdr`) | 4 份新构建里分别是 `AyqhIdr` / `QtDKYSO` / `ryieWP_` / `mYmmgLx` —— **每构建都变**。改用结构规则识别(已知 #46)。 |
| **"按模块 id 配对就能跨构建对齐"** | 同 #43;且我用"模块 id 相等"做校验时**自己误判过一次**(看到 35/37 不一致就以为配对错了)—— 实际上 id 不一致是**预期行为**,不能用来否定配对。正确校验见已知 #48。 |
### 2026-10-12 图标点选(2408)新增排除
| 假设 | 否定证据 |
| --- | --- |
| **"2408 的 12/50 是 YOLO 召回不足 / patch 太小 / box 偏移导致点错"**(旧 §五 的头号方向) | **目视逐点核对 8 次跑 / 24 个点 24/24 全对**(已知 #64):把落盘的提示图切 3 片,与"实际点击点 ±32px 的背景 patch"并排放大,每次每个点都落在与提示**同序**的目标图标上;连 4 次 `12` 与 2 次 `50` 也都是全对。→ **点错不是自变量**。 |
| **"1ms 与 mliev 的图标课题配置不同(答案坐标系 / 格式 / 元素表)"** | 两侧 dump **逐字段相同**(已知 #69):`data_type=["DynAnswerType_POS"]`、`size_2d=[672,480]`、底图 672x480、提示图 170x50、`ins_elem_cfg` 只有"提示图元素 id=1"、`verify_trigger_cfg={verify_icon:true}`。→ 配置侧解释不了两靶差异。 |
| **"提示图取错了(应当用 `dyn.sprite_url`,我们改写了底图 URL 的 `img_index`)"** | 同课题里两条 URL 的 `image=` token **本来就相同**,取回的提示图 **md5 逐字节一致**(已知 #70)。→ 这是个真实但不影响结果的偏差。 |
| **"轨迹落在末槽时 `chunk2` 仍要补前导逗号"** | 旧写法在该构建上拼出 `{"cd":[<37 槽>,<traj>,],` —— **非法 JSON**(已知 #65)。真机是 `JSON.stringify` 语义:逗号只在**槽与槽之间**,两端空区间都不补。已修 + 回归。 |
---
## 四、当前实现(纯算单一路径)
@@ -270,6 +290,47 @@ TencentCaptchaClient(telemetry_mode="python_keyed") # 默认
### 🆕 2026-10-12 优先(按案例重做后的收尾,按成本排序)
#### 🔴 2026-10-12 晚:2408 图标点选收尾(下一轮从这里开始)
现状(判读见 §三 新增排除 + 已知 #64~#72 + 专文 **`har/1ms_dianxuan/ICON2408.md`**):
**图标链路本身已经通了,而且"点得不准"这条怀疑已被定量排除** ——
* 可复现靶子 aid **190758559**:本轮累计 **正确作答 22 次 → `0` × 20**(另 2 次 `Connection reset by peer` 网络层失败);
而**故意扰动 5 次(交换前两点 ×2 / 整体平移 50px ×2 / 75px ×1)→ `50` × 5** —— 靶子对我们非常稳定,是理想回归台;
* **点击精度**:点击点离「图标暗色笔画质心」仅 **2.2px(1ms)/ 3.3px(mliev)**;
* **服务端容差**:给答案整体平移 `25px` 仍 `0`、`50px` 才 `50`(已知 #71)→ 精度富余**一个数量级**;
* 1ms 上三次 `12` 的答案里,每个目标类都有 **top-1 概率 = 1.0** 的候选;判读图 **24/24 全对**(已知 #72)。
→ 所以 `12` / `50` **都不是"点错"**:`50` = 答案被否(#66 已用"故意答错"负对照标定),
`12` = 包级/会话级拒答(答案还没被裁判)。1ms 在同一时段、同一代码下会在
`0 / 50 / 12` 之间漂移,且一次爆发里呈现"前 2~4 次 `0`、之后 `12`"。
**下一轮只剩两件事**(按成本排序):
1. **判 `12` 是不是"按 aid+IP 的令牌桶/频控"**(唯一还有区分度的自变量)。做法:
静默 ≥20 分钟后**只发 1 次**看是否回到 `0`;再对"同一轮里成功次数是否有限"做复现。
本轮 `send_campaign.py` 已记录**每次求解的 prehandle 次数**(`points.json.prehandles`),
可直接把「请求量 ↔ errorCode」画出来。**注意:连打会自伤,测 1ms 时务必拉开间隔。**
若确认是频控 → 结论就是"1ms 需低频使用,回归一律用 190758559",不必再改代码。
2. **只在需要时**再追"为什么 1ms 会在正确答案上给 `50`"(`50` 的语义是答案被否,
但已知 #72 表明答案是对的)。优先级低于 1,因为它已不影响交付能力。
复验入口(**仓内工具**,2026-10-12 起替代 /tmp 一次性脚本):
```bash
# 批量真实发送 + 落图 + 统计(支持 --offset 容差标定 / --swap 故意答错 / --kind icon|text|slider|any)
.venv/bin/python scripts/verify/send_campaign.py --target mliev --kind icon --n 8
.venv/bin/python scripts/verify/send_campaign.py --target mliev --kind icon --n 2 --offset 25,0
.venv/bin/python scripts/verify/send_campaign.py --target mliev --kind icon --n 2 --swap # 负对照,期望 50
# 目视判读图(列 = 提示图第 j 个目标 vs 第 j 个点击点 patch;红框上标了 #1/#2/#3 顺序)
.venv/bin/python scripts/verify/judge_icons.py har/1ms_dianxuan/icon_campaign/<tag>
```
产物默认写到项目内 `har/1ms_dianxuan/icon_campaign/<tag>/`(`har/**` 只跟踪 `.md`,
所以图片不入库但留在项目树里可复核);本轮的原始产物已就位。
---
### 既有优先项
0. ✅ **已完成(2026-10-12)—— 纯离线生成已打通**。做法:真 Chrome 取「同会话构建 +
同会话 `TDC.getData(true)`」按位置对齐,拿到 37 个语义名 -> 真值(38/38 槽,已知 #54),
再固化成 `tcaptcha/tdc_values.py`(分**静态画像 / 会话量 / 每次采集量**三层)。
@@ -345,7 +406,11 @@ TencentCaptchaClient(telemetry_mode="python_keyed") # 默认
3. **补齐新版明文语义 + 槽位表**:语义(哪一槽是 UA / 屏幕串 / WebGL / 轨迹 / 时间戳)已从
已知 #30 的真机明文基本对齐;**关键是每份构建的槽位序**(已知 #31)——
见上面 1(b)。分析入口:`scripts/analyze_collect_layout.py`。
4. **实现 2408 图标点选**:按 1ms 图标类别重训 `yolo_detector` + `icon_classifier`。
4. ✅ **已完成(2026-10-12)—— 2408 图标点选端到端打通**:纯 ONNX 三件套
(YOLOv8 召回 + ResNet18 13 类分类器 + 全局非冲突组合搜索)直接吃现成权重,
**不需要重训**(原计划"按 1ms 图标类别重训"已被实测推翻:现权重在 1ms 与 mliev 上
点位都正确,见已知 #64)。端到端证据:可复现靶子 aid 190758559 **8/9 = errorCode=0**(#67)。
剩余:**1ms aid=195672344 的 12/50**(与图标链路无关,见本页最上方"2408 收尾")。
5. ✅ **已完成(2026-10-12)—— 滑块 (2401/2402)**:不用模板匹配,改用**拼图块内容与缺口做 ZNCC**
(缺口 = 同一块内容被压暗,真缺口相关性最高、干扰缺口次之)。答案格式从课题 JSON 的
`move_cfg.data_type` 取(`DynAnswerType_POS`,坐标=背景图原始像素),轨迹走`drag_trajectory_points`。