Files
sanguo_vnpy_v2/audit/20261003_recent2days.md

342 lines
35 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 最近两天 commit 纯代码审计报告(2026-10-03 23:10 定时任务)
- **仓库**:`/Users/chufeng/.openclaw/sanguo_projects/sanguo_vnpy_v2`(master,审计基准 HEAD = `7f9b4133e5a4a104c0715d6a0849a4847d186e0c`)
- **时间窗**:2026-10-01 23:23:14 ~ 2026-10-03 22:05:02(按任务要求取最近 48 小时,全窗口有提交,无需顺延)
- **规模**:59 个提交 = 代码类 39(feat/fix/refactor/test/ops)+ 纯文档 20(docs)
- **方法**:按模块分 7 簇并行只读审计(仅 git show / git diff / Read / grep,未运行测试、未安装依赖、未修改任何文件);主审对全部 5 条在役 P1 逐一亲自复读源码复核属实后才定级
- **铁律**:本报告只输出处置意见,不执行任何修复。行号一律给出**该提交版本行号 + 是否对 HEAD 仍有效**(各发现已逐一核对后继变更)
---
## 一、总体结论
**无 P0。** 活跃在役发现:**P1 × 5、P2 × 19、P3 × 33**;另有 **8 条缺陷在窗口内被后续提交自我修复**(2 P1 + 4 P2 + 1 P3,修复质量经复核有效)。
三天代码整体质量高:测试与实现同提交、护栏/门禁设计有层、敏感信息纪律好(token 全走 env、QMT 密码走 DPAPI→env→内存从不落盘落 argv)。主要风险集中在两处:
1. **P4-3 语料漏斗(10-02 一天落地的 5 件套)是本次风险最集中的新面**:崩溃窗口丢数据、`--limit` 假开关、`--llm-cap` 溢出永久丢弃三条 P1 同文件(`scripts/data_platform/corpus_funnel.py`),且生产接线脚本未启用 token 断路——「文档承诺的护栏」与「实际存在的护栏」不一致。
2. **两处"语义性静默失效"**:`all_weather` 止损的涨停观察分支被 P0-4 前视修复**构造性打死**(提交说明未披露);分解产物动态注册链绕过全部护栏直通 vnpy 的 `eval` 汇点(纵深防御缺口)。
另需肯定:本窗口内两笔 P1(decompose 半成功 500、manifest 缺路径炸批)均由簇内后续提交修复并钉了测试——自愈机制在正常工作。
---
## 二、活跃 P1(5 条,均已主审复核源码坐实)
### P1-1 漏斗水位先行前移 + 数据延迟提交:崩溃窗口内事件与候选**永久静默丢失**
- **commit**:`65e5c02916e9597a6c4263cb697e0a4bf5bcb08d`(feat(data): 漏斗主体 corpus_funnel)
- **坐标**:`scripts/data_platform/corpus_funnel.py:213,217,219-220`(对 HEAD 7f9b413 仍有效);`scripts/data_platform/corpus_download.py:772`
- **证据**(主审复读确认):
```python
cd._absorb_new("events_llm", events, ledgers, recents) # L213 只进内存 DayBuffer
ctx.unit_done(domain, d) # L217
wm[domain] = d # L219 水位立即写盘
_save_watermark(wm) # L220
```
而事件/账本行要等 `corpus_download.py:772` 的 `if self.units % FLUSH_EVERY == 0: self.commit()`(FLUSH_EVERY=50)或 main 优雅出口才落盘。
- **机理**:每处理一天水位立刻持久化,该天的 events_llm/events_in 行与 marker 还在内存(最多差 49 unit)。kill -9/OOM/非 WallClock/BudgetStop 的未捕获异常会跳过 commit 与 `_save_pending`:水位已前进 → 次日起永不再重走 → 窗口内全部词表事件与新鲜候选**永久丢失**。本域 append-only 永不重算,丢失即永久;stats/integrity_gate 均无字段暴露该缺口。优雅停机路径无此问题(异常→commit→remainder 回写)。
- **处置建议**:`_save_watermark` 挪进与 commit 同一 checkpoint 边界,或每 domain-day 处理完即 `ctx.commit()`;main 加兜底 `except Exception` 落 emergency remainder 后再 rc=1 退出。
### P1-2 `--limit` 是假开关:文档承诺「LLM 调用数上限」但全链零检查
- **commit**:`65e5c02916e9597a6c4263cb697e0a4bf5bcb08d`
- **坐标**:`scripts/data_platform/corpus_funnel.py:296(argparse help),313(唯一引用点),235-238(lane 循环)`;对照 `scripts/data_platform/corpus_download.py:762-763`
- **证据**(主审复读确认):`Ctx.budget_exhausted()` 的实现是 `return self.limit is not None and self.stage_units >= self.limit`(corpus_download.py:763),corpus_download 自己的 10 处 lane 都调用它;**corpus_funnel.py 全文对 `budget_exhausted` 零引用**(grep 证实),`args.limit` 仅在 :313 构造 Ctx 时传入后再无人读。
- **机理**:`corpus_funnel --limit 5` 会把 pending+fresh 全量串行打完(仅受 `--until` 墙钟约束),「冒烟」语义完全失效;而 marker 抑制(`unit_done` 的 `if mark and self.limit is None`)倒是生效——制造「没落 marker 但烧光全部 LLM 调用」的最坏冒烟形态。tests 中亦无 `--limit` 生效断言。
- **处置建议**:`_llm_lane` 循环顶部补 `if ctx.budget_exhausted(): break`;或删掉 `--limit` 参数。二选一,勿留假开关。
### P1-3 `--llm-cap` 实为「逐日×逐域」截断,溢出部分**永久静默丢弃**
- **commit**:`65e5c02916e9597a6c4263cb697e0a4bf5bcb08d`
- **坐标**:`scripts/data_platform/corpus_funnel.py:215-216`(对 HEAD 仍有效)
- **证据**(主审复读确认):
```python
fresh_cands.extend(cands[: args.llm_cap]) # L215 每日×每域截断
stats["candidates_fresh"] += len(cands[: args.llm_cap]) # L216 只统计保留部分
```
help 文案(:298-299)宣称「每夜新鲜候选上限(默认 200)」。
- **机理**:截断在每日×每域粒度执行——回填/首夜全史走水位时,一夜实际可入队 200×天数×2 域(与「每夜 200」契约相去甚远,成本面);更重的是 `cands[200:]` 尾部既不入 pending 也不进任何计数,水位前移后**永远不会被第二层看到**,丢弃完全不可观测。公告标题含高频信号词(合同/担保/诉讼/立案…)时单日超 200 是常态。丢的是漏斗自身覆盖面,gate 无法发现。
- **处置建议**:cap 语义改「每夜总量」:入队前统一截断并记 `candidates_dropped`;或溢出候选追加进 funnel_pending.jsonl 次夜续。
### P1-4 分解产物动态注册链**零护栏直通 eval 汇点**(纵深防御缺口)
- **commit**:`e06bf6c522639fe015b4321e7c6f35fa1c0555eb`(fix(factor): D2 动态表达式注册链)
- **坐标**:`sanguo_factor/monthly_batch.py:61-63`(1b27226 后文件未再改,对 HEAD 仍有效);汇点 `vnpy_v4.4.0/vnpy/alpha/dataset/utility.py:253`
- **证据**(主审复读确认):
```python
expr = params.get("expression") # yaml 最新版 params 原文
if not expr: return None
register_factor(name, expr, category_for_source(...)) # 无任何 precheck
```
汇点:`other: DataProxy = eval(expression, {}, d)`——globals 为空 dict 时 CPython 自动注入 `__builtins__`,未过护栏的字符串即任意代码执行。
- **机理**:resolver 只按 source 分类,对表达式本体不做 `precheck_expression`。当前唯一写入方 routes_pipeline 经 check_candidate 把关,但该 yaml 是运行期可变文件,任何其他写入者/手工编辑/未来旁路一旦写入未消毒字符串,下次月度批 eval 即任意代码执行。precheck 正是现成的 AST 白名单,同函数已 import factor_guard 却只用其 category_for_source。
- **处置建议**:`register_factor` 前对 expr 跑 `precheck_expression`(违规记 skipped_unregistered+stderr);顺带校验 source 与 derive_source(expr) 一致。另 resolver 取 `versions[-1]` 无视 effective_from/to 窗口,建议一并对齐 effective_version 纪律。
### P1-5 all_weather 止损「昨日涨停打开尾盘卖出」分支被前视修复**构造性打死**(提交说明未披露)
- **commit**:`6251451a761faa2aa50d1e91d0985586bd984751`(fix(strategy): P0-4 前视修复)
- **坐标**:`sanguo_portfolio/strategies/all_weather.py:145-159(9:05 选名单)、169-182(14:00 判板)、485-493(_limit_status)`(至 HEAD 未再改,行号对 HEAD 有效)
- **证据**(主审复读确认):9:05 用 `get_limit_status_batch(hold, T-1)` 筛 `yesterday_hl_list`(is_limit_up=True);14:00 `stop_loss` 对同一批股票查**同一 T-1 日期**的同一个确定性日线函数(:175 → :493 → 同一 `get_limit_status_batch`,日 bar 不可变)——结果恒为 True,`else: 涨停打开,卖出`(:180-182)不可达。
- **机理**:修前该分支查 T 日 bar(带前视、可达);修后回测与实盘一致地**永不触发**。「昨日涨停打开尾盘卖出」这一风控特性在全环境实际退役,且待执行的重跑重评将把死分支行为固化进正式回测数字。提交说明只写「缺失→跳过涨停观察」,未披露分支恒死。
- **处置建议**:需设计拍板——14:00 改查当日盘中实时状态(tick/最新价 vs high_limit,provider 已有 get_current_tick 雏形),或显式删除死分支并在处置档记录特性退役。当前回测语义与 docstring(:163)相悖。
---
## 三、窗口内自我修复项(8 条,修复经复核有效,无需再动)
| 原 commit | 级别 | 缺陷 | 修复 commit | 复核结论 |
|---|---|---|---|---|
| `4296b4f0198559655acf55380d834162c3032f55` | P1 | building 卡二次分解撞状态矩阵 ValueError → 500 半成功(registry 已写、卡片未动) | `f740999` I-1 | HEAD:944-948 已加守卫,配套测试钉住;建议把「allowed 状态集×矩阵相容性」固化为 store 层单测 |
| `dbe6623e81de850aebc94766a5d00cc4820f0fe2` | P1 | monthly_batch `--manifest` 缺路径 FileNotFoundError 炸批(违背 fail-soft 宣称) | `1b27226` m6 | HEAD:112-118 已加 exists 守卫+stderr 告警,test_main_missing_manifest_failsoft 钉住;但只补了「缺路径」一态(见 P2-11/12) |
| `1c5f1ab53e989cc5ae8debf733d8f75cfe1baeb6` | P2 | load_domains 只捕 OSError,坏 YAML → draft/save 双端点 500 | `1e3579b` | HEAD:54 已 `except (OSError, yaml.YAMLError)` |
| `a81e1b6af7ca3abc30e93ab5f820efbe87cc5e18` | P2 | save 端点 sentence 无长度上限(draft 有 500 闸,不对称) | `1e3579b` | HEAD:848-850 已补,test_save_sentence_too_long_400 转绿 |
| `9aa104ba9fd8c1a042325feeb53838ff1bc613c0` | P2 | 同步 time.sleep 在事件循环内阻塞 2-4 秒 | `1e3579b` | 全路径已 `await self._sleep`;建议保留 Awaitable 类型注解防回退 |
| `9aa104ba9fd8c1a042325feeb53838ff1bc613c0` | P2 | httpx.TransportError 裸逃逸穿透 502 契约 | `1e3579b` | 已纳入重试链,耗尽出口 LLMError,attempts 有界 |
| `13f3124a4b13dcc1a5791215fd92c9b4d734141e` | P3 | 反馈轮 prompt 不带在库名单,易空耗 3 轮全灭 | `f740999` M-2 | HEAD:27-52 已带 taken 名单(截 120) |
| `a81e1b6`(draft 先例) | P3 | 同上 draft 端点 sentence 上限先例 | `1e3579b` | 双点对称 |
**max_rounds=3 专项核查结论**(任务书点名项):修复完备。唯一出口 `not failed or rounds >= max_rounds`,LLM 调用 ≤3 次,test_loop_stops_at_max_rounds 钉住;内层 client while True 亦受 attempts/healed 双旗约束有界,无死循环路径。
---
## 四、活跃 P2(19 条)
### LLM 模块簇
**P2-1 「429 Retry-After」从未实现,提交说明与测试名双重失真**
- commit `9aa104ba9fd8c1a042325feeb53838ff1bc613c0`;`sanguo_api/llm/client.py:90-93`(HEAD 行号,至 HEAD 未再改);测试 `tests/api/test_llm_client.py:49-58`
- `_post` 只返回 `(status_code, text)`,headers 全程丢弃;测试 fixture 给 Retry-After "2" 恰与固定退避 `_BACKOFF_SECONDS[0]=2.0` 重合,断言靠巧合通过。provider 要求等 30-60 秒时仍按 2/4 秒重击。
- 建议:`_post` 带回 headers,429 解析 Retry-After(非数字回落固定退避),修正测试名。
**P2-2 L5 尾逗号清洗不感知字符串,可静默改写 JSON 字符串值后当成功返回**
- commit `46d76e75b7de3b945451cb62ab6a21ef45287087`;`sanguo_api/llm/json_utils.py:13,66`(对 HEAD 有效)
- 实测反例 `{"s": "a, }",}` 被 L5 改写为 `{"s": "a }}"` 解析成功——字段值损坏且外层看到的是成功。hypothesis_decompose 链路更自动,无人审兜底。
- 建议:清洗改字符串感知状态机,或至少对 L5 救回结果打「降级解析」日志。
**P2-3 robust_json_parse 对非 str 输入裸逃逸;上游 content=null 穿透 502 契约变原生 500**
- commit `46d76e7`(json_utils.py:57,29)+ `9aa104b`(client.py:67-73 `content=None` 放行)→ `routes_pipeline.py:839-842` 只捕 LLMError/ValueError
- openai 兼容端点空回复返回 `"content": null` 并不罕见,此时 TypeError 直穿 FastAPI 500。
- 建议:入口 `isinstance(text, str)` 防御;client 对 None content 直接 raise LLMError 走 strict 重试。
**P2-4 「坏 YAML fail-soft」只挡语法错:合法 YAML 但形状不对仍 AttributeError→500**
- commit `1e3579b64e65088e33e907aea631e4134985c85c`;`sanguo_api/hypothesis_card.py:53-56`;爆炸半径 `routes_pipeline.py:834`(`_wizard_domains()` 在 try 块外)
- 顶层 list/scalar 或 `domains:` 为 list 的合法 YAML → `.get`/`.keys()` AttributeError,draft/save 双端点 500。
- 建议:`isinstance(manifest, dict)` 防御一行闭环 fail-soft 宣称。
### pipeline 假设卡簇
**P2-5 状态转移矩阵校验 SELECT→UPDATE 两步非原子,并发可绕过 graveyard 终态禁令**
- commit `9389a7b9d5e5942bd5acba441492560776cdde76`;`sanguo_portfolio/pipeline_store.py:276-287`(后未改,对 HEAD 有效)
- UPDATE 不带 `AND state=?` 守卫、无事务包裹:并发下末写者胜,可产出「building 态带 death_reason」甚至把 graveyard 迁出——D3 禁复活在竞态下不成立。同文件 graduate 端点有 `_GRADUATE_LOCK` 先例未复用。
- 建议:下沉为单条条件 UPDATE(rowcount==0 二次 SELECT 区分原因),或仿 `_GRADUATE_LOCK` 加互斥。
**P2-6 decompose「registry 落盘 + 卡片转 building」跨存储两步写不原子且无锁**
- commit `4296b4f0198559655acf55380d834162c3032f55`;`sanguo_api/routes_pipeline.py:944-948`(HEAD 仍无锁/无事务,本条在 HEAD 成立)
- save_registry(yaml) 与 update_hypothesis_state(sqlite) 无共享事务;`load_registry`→`save_registry` 是无锁读-改-写。中途失败留「registry 有因子、卡片仍 queued」可重复注册;并发 decompose 同卡整文件覆盖丢更新。incubating 候选不直接涉资金,故 P2。
- 建议:短期加 graduate 同款按卡互斥;中期考虑 pending 意图行/版本号 CAS。
**P2-7 反馈循环批内无表达式查重:同批「同构换皮、异名」候选双双过门一次成型**
- commit `13f3124a4b13dcc1a5791215fd92c9b4d734141e`;`sanguo_api/hypothesis_decompose.py:130-131` + `routes_pipeline.py:909-916`(HEAD 行号)
- `claimed` 只收名字;dup_violations 的对照集 `library_exprs` 不随本批 passed 增长——防换皮门(7e93c5b 核心卖点)在同批维度被绕过,首批污染已落 registry。
- 建议:循环内把已通过候选 expression 增量并入对照集,一行级改动。
### factor 分解器 #84 簇
**P2-8 precheck 白名单漏 JoinedStr/FormattedValue/Await/Yield:f-string/await/yield 零违规过门**
- commit `62c797534aae85d418b2701c6284d2a8d0ddcd92`(至今未修);`sanguo_factor/factor_guard.py:56-60`(HEAD 行号)
- stdlib 实测 `precheck("f\"{close}\"")==PASS`、`precheck("await cs_rank(close)")==PASS`。不构成代码注入(内部节点仍被查),但非法方言拿到「合法候选」身份进注册表,直到 eval 阶段才报单因子 error,护栏「违规结构化返回」契约被击穿。f740999 补了 Tuple/List/Set 仍漏这三个。
- 建议:`ast.JoinedStr, ast.FormattedValue, ast.Await, ast.Yield, ast.YieldFrom` 入 `_BLOCKED_NODES`,钉 f-string/await 拒绝测试。
**P2-9 IC 正交闸可静默 no-op:「查过且干净」与「根本没查成」报告不可区分**
- commit `a1caccf1b1233bbccc1d9c0f2edec639b645aa75`;`sanguo_factor/ic_gate.py:58-73`(未改,对 HEAD 有效);接线 `monthly_batch.py:138-146`
- 新因子 parquet 缺件(batch_eval 单因子失败时不落盘)→ 该因子整体 `continue`;report 无 `skipped_missing_values`/`compared_pairs` 字段,monthly_batch 仅 flagged 非空才打印——系统性 eval 失败呈现为绿灯。
- 建议:补计数并在 `checked < len(new_names)` 或比对数为 0 时 stderr 显式告警。
**P2-10 D5 死亡回写「卡片不存在」路径零痕迹返回 False,调用点忽略返回值**
- commit `403a043b8c0ba38b6d4cac2b196a75894e5c283a`;`sanguo_factor/version_registry.py:151-162,240-241`;根源 `pipeline_store.py:278-279`
- `--pipeline-db` 缺省 `data/pipeline.db` 为 cwd 相对路径且 _connect 自动 CREATE 空库:从错误目录跑 CLI 转移时,因子落 graveyard 而卡片回写静默 no-op,还顺手生成空库;死假设可继续孵化新因子,无事件可审计。
- 建议:False 路径显式 stderr+registry_events.jsonl 附记;`--pipeline-db` 绝对化或存在性预检。
**P2-11 m6 manifest fail-soft:缺路径比坏 manifest 更安静,且与独立 CLI 退出码语义倒挂**
- commit `1b27226ab619d18e8ef62bda1d455e9ee3b9a8a3`;`sanguo_factor/monthly_batch.py:112-118`(对 HEAD 有效);对照 `data_gap_check.py:106-108`
- 缺 manifest → gaps={} 完全安静(不写 data_gaps.json、不触发 gap_issue)——数据侧最需告警的场景零输出;独立 CLI data_gap_check.main 同情形 exit 1,两处契约相反。默认路径 cwd 相对,调度换目录即常驻 fail-soft 分支。
- 建议:缺 manifest 落 `{"manifest_missing": true}` 标记件;与 CLI 退出码对齐;文档化绝对路径 env。
**P2-12 manifest 存在但格式坏时月度批仍炸(fail-soft 契约只补了「缺路径」一态)**
- commit `dbe6623e81de850aebc94766a5d00cc4820f0fe2`;`sanguo_factor/monthly_batch.py:112-114`(HEAD)+ `data_gap_check.py:24-26,41-43`
- 语法坏 → yaml.YAMLError;解析成标量/列表 → `manifest.get` AttributeError——两态均无捕获,批前崩溃与 P1(已修复项)同杀伤。
- 建议:缺口比对整体 try/except(stderr 告警+gaps={} 照跑);补坏 YAML/非 dict 两态测试。**P2-11/12 同根同处置,可一刀修。**
### factor #70 簇
**P2-13 缺口单去重三重脆弱:首页 50 条上限 + 单永不关闭 + 查单失败放行,无速率上限**
- commit `dbe6623`;`sanguo_factor/data_gap_check.py:66-82(find_open_issue),85-94(maybe_open_gap_issue)`(对 HEAD 有效)
- open issue 只增不减;超 50 条后目标单跌出首页,`find_open_issue` 静默失明,同一指纹每月重复开单;LIST 网络异常 `except Exception: return None` 后照走 open(fail-open)。全仓无任何关单代码。指纹机制本身干净(sorted 行序无关,测试钉死;月频 32bit 碰撞可忽略)。
- 建议:search API/翻页兜底;异常与「确认不存在」区分(异常时跳过 open);按指纹落本地 append-only 台账作第二道去重。
### data 漏斗簇
**P2-14 rc() 优先级令「墙停/token 断路 checkpoint」被单次 LLM 噪声失败覆盖成 rc=1**
- commit `eb6475b1d7d0472718af896c9d0b6bb40e2b1613` + 表现层 `65e5c02`;`corpus_download.py:803-809`、`corpus_funnel.py:246,367`(对 HEAD 有效)
- 夜批出现 1 次瞬时 LLM 失败(`ctx.failed += 1` 不熔断继续跑)即可把正常 checkpoint 的出口 rc=3 覆盖成 1「致命」——09-19 runbook 已记录过的 corpus_download 同款坑在漏斗上复刻,监控分流失真。
- 建议:checkpoint 状态优先于噪声失败定级,或单独输出 checkpoint 标志供监控解析。
**P2-15 词表否定守卫只拦「紧邻」否定:常见间隔措辞系统性漏拦,误判以 confidence=1.0 定格且无第二层纠错**
- commit `8bf935b1a0349250d03dc076af1b4a4387f6e81a`;`scripts/data_platform/funnel_lexicon.py:44-45,55-63,79-83`(对 HEAD 有效)
- `prefix.endswith` 只在否定词紧贴关键词时生效:「尚未扭亏」→ earnings_pre_up/pos、「仍未增持」→ holder_increase/pos、「已终止的质押」→ pledge_new/neg——**方向可能完全相反**的事件以 model=lexicon、confidence=1.0 直落 events_llm,且 lexicon 命中被排除出 LLM 候选,无纠错路径。
- 建议:窗口扩 3-4 字改 contains;lexicon 命中但窗口内有否定词的降级为 LLM 候选;先补「尚未/仍/不排除」负向测试。
**P2-16 生产接线未启用 token 预算断路:唯一护栏只剩 `--until` 墙钟**
- commit `e47dddd336a7c1f54a639f95a1b33d15ddf67ecd`;`scripts/nas_sync/run_corpus_standalone.sh:111`(对 HEAD 有效)
- 本簇头号特性(eb6475b token 断路)在生产命令无参数落地,叠加 P1-2(--limit 假开关)与 P1-3(逐日 cap),首夜全史回填的 token/费用实际无上界(时间有界)。runbook 宣称「token 预算断路 rc=3 次夜续」与实际不符。
- 建议:生产命令补 `--token-budget`,或修订 runbook/spec 文案如实声明「生产仅墙钟护栏」。
### strategy 簇
**P2-17 `_previous_date_str` 缺失时静默回落当日 T:momentum 新加的 None 守卫实际不可达,前视可静默回归**
- commit `6251451`(守卫新增)涉及 helper `all_weather.py:629-642`(旧有);`momentum_timing.py:151-156`
- bullet_trade 引擎首日 `previous_date` 可能保持 None(get_trade_days 失败仅 warning、async_engine 首日不设),此时 helper 回落**当日 T**——panel 上界退化为回测当日收盘,恰是要根除的前视,且守卫要求 current_dt 同为 None 才触发(实际不可达)。`factor_topn.py:109` 注释自证该回落路径真实存在;`all_weather.py:632`「bullet_trade context 无 previous_date 属性」注释与 0.9.2 实际相悖(陈旧注释)。
- 建议:数据上界改显式 T-1 推导(对齐 factor_topn 自算口径);fallback 分支加 warning;勘正两处陈旧注释。
### qmt 灾备源簇(dbf57f2 回库 5 主件)
**P2-18 模拟柜台资金账号 66639661 硬编码回库**
- commit `dbf57f2fd0f9c518c8c0add766ae9c76a79c1e30`;`scripts/qmt_relogin/qmt_gate_common.py:14`、`qmt_relogin.py:41`(HEAD 行号相同;回库后至 HEAD 零改动)
- 经仓库内文档佐证为**模拟柜台账号**(余额 9999998.51、userdata_mini 模拟端),且 HEAD 全仓已扩散 32 文件(setclip_acc.py 同号在先),故定 P2 而非 P0。
- 建议:若确认永为模拟账号,新代码改读既有 `BIGQMT_ACCOUNT_ID` env;若该号实际具备实盘属性或未来复用,升级 P0 并轮换/更换账号。
**P2-19 探活撤单失败仍判 GREEN、exit 0:残留 live 委托仅日志 CRITICAL,进程级信号被掩盖**
- commit `dbf57f2`;`scripts/qmt_relogin/qmt_probe_0915.py:96-103,175-179`
- place() 下真实委托(0.01 买价),cancel 失败时订单仍 LIVE 但 verdict=GREEN、return 0——监控只看灯色/退出码会漏掉残留单。资金风险趋零(0.01 不可能成交+日终清算),灾备源标准定 P2。
- 建议:cancel 失败时 verdict 降 AMBER 或 exit 2,让 GREEN =「委托确认且撤单干净」。
---
## 五、活跃 P3(33 条,简式)
**LLM 簇(5)**
1. `46d76e7` json_utils.py:63-67 — L4/L5 修复不叠加(并行候选非累积降级);注释「尾随垃圾重截一次」未实现
2. `46d76e7` json_utils.py:29 — `_balanced_braces` 以首个 `{` 为起点,起点落在字符串内则配平错位(假阴性,仅多 502)
3. `9aa104b` client.py:67-68,115-118 — 同一响应体解析两次;每 attempt 新建 AsyncClient 无连接复用(效率)
4. `9aa104b` client.py:80-88 — 400 参数自愈为文本子串启发式且与 429/5xx 共享 attempts 预算(有界、语义混杂)
5. `7b489d1` client.py:39-40,68 — want_usage 的 usage 可为空 dict,计量侧无法区分「0 token」与「上游没给」;联合返回类型不友好
**pipeline 簇(3)**
6. `7a89632` pipeline_store.py:227-228 — 卡 id=秒级时间戳+2 字节 hex,同秒碰撞 ~1.5e-5 → IntegrityError 500;`card["id"]` 通路无格式约束
7. `a81e1b6` routes_pipeline.py:858 — save 端点 source 零白名单零上限,任意字符串落库永久回显
8. `a81e1b6`/`4296b4f` routes_pipeline.py:846 — 502 detail 透传上游 LLM 响应体前 200 字(可能带出上游端点/账号上下文;api_key 不泄漏已核实)
**factor #84 簇(5)**
9. `7e93c5b` factor_guard.py:165-166,266,275 — 整树 <8 节点的交换律重排同时躲过 dup_exact 与 dup_subtree(小因子换皮漏检,靠 IC 闸兜底而 IC 闸自身有 P2-9 缺口)
10. `a1caccf` ic_gate.py:38-42 — 有效 corr 日数无下限:常数截面日滤除后少数日均值即可触发置疑
11. `a1caccf` monthly_batch.py:133-137 — origin=decomposer 新因子判定双向漂移:分解因子每月重考永不收敛;手工升版即无声退出闸视野
12. `e06bf6c` monthly_batch.py:38-65,70 — plan_batch「纯函数」docstring 契约被 resolver 全局注册副作用打破(跨调用/测试泄漏)
13. `62c7975` factor_guard.py:54,126 — NAME_RE `$` 允许尾换行(`"abc\n"` 过闸),公共门 API 层潜在缺陷,现调用方 strip 兜住
**factor #70 簇(7)**
14. `dbe6623` data_gap_check.py:85-94 — 双机(NAS+VPS)同日各跑 --gap-issue 的 check-then-open 竞态可开重复单(月频+默认关,概率低)
15. `f9914ca` monthly_review.py:26 vs :158 — `_PROMOTION_BAR=2.0` 注释宣称「单一事实来源」,pre_gate_table 实为另一处硬编码 2.0(两份拷贝);负 t 侧无镜像门边带
16. `367b4cf` exam_gate.py:41-49 — 缺周期跳过使判定可退化为单周期对比即 SUGGEST_PROMOTE;负 ICIR 按「序」可胜(最终人裁,实害有限)
17. `367b4cf` exam_gate.py:97,100-105 — 同日重跑同候选覆盖既有 md 报告(label 不含 run_id),晋级证据链失去历史
18. `d15653d` config/factor_registry.yaml:108-121 — promotion_t=26.32 条目本体无 evidence_run 指针(出处只在 docs;墓园条目有此惯例)
19. `d15653d` composite_library.py:91-93 — 等权合成实为 12 源交集语义:任一源缺→该股当日 null,分母恒 12 不重归一(文档化已知限制,易误读为可用成员等权)
20. `dbe6623` data_gap_check.py:71-72 — 内网 Gitea 地址 fallback 硬编码第二份副本(与 version_registry 同值暂无漂移)
**data 漏斗簇(5)**
21. `65e5c02` corpus_funnel.py:275 vs :231 — 「喂模型文本先落盘」契约与实现顺序不符(调用后才入内存缓冲,随 commit 才落盘)
22. `1ea143e` integrity_gate.py:88-89,128-129 — 空窗=全绿:断供超 7 日后 L2 六项 critical 全部 vacuous pass,gate 绿不能当管道存活证据(新鲜度豁给监控是记录在案的设计决策)
23. `e47dddd` run_corpus_standalone.sh:112-113,123-124 — gate 1/2、funnel 0/1/3 调用侧仅回显不分流;锁让路与 checkpoint 共用 rc=3
24. `65e5c02` corpus_funnel.py:285-288,32 — `_dump_raw_fail` 从未被调用(死代码,让人误以为坏响应有留痕)+ Path 导入未用
25. `e47dddd` run_corpus_standalone.sh:101,105-107 — LLM key 经 `docker run -e` 传递,argv/`docker inspect` 短暂可见(引号处理正确、日志面无泄漏,常规实践)
**strategy/data 簇(2)**
26. `7f9b413` strategy_checks.py:245 — logs_stale 迁 trading_day 后 docstring 仍写「仅工作日班评」,与实际闸门语义不符
27. `434f7bc` akshare_static_download.py:984-999 — margin 守卫不覆盖「feed 已越过请求日但该日块未发布」的中段缺块形态(提交说明已声明属有意边界,记录项)
**qmt/docs 簇(6)**
28. `dbf57f2` qmt_relogin.py:174 — 启动行明文打印登录用户名入日志(密码仅打长度,处理链本身是亮点)
29. `dbf57f2` qmt_gate_common.py:57,118 / qmt_relogin.py:115,144 — requirepass 正则无 None 守卫,redis.conf 漂移时 AttributeError 自爆(灾备恢复恰是配置最易漂移场景)
30. `dbf57f2` qmt_relogin.py:125-130 — flush_stale_queue 对解码失败项静默 continue 后整队 delete,绕过「订单类绝不删」守卫
31. `dbf57f2` qmt_gate_common.py:15,113,121 等 — 灾备源写死盘符路径;qmt_sentinel.py:90 内部域名(布局契约未文档化)
32. `22b4548` p70 计划文档 diff — 内网 Gitea IP+端口入文档(全仓 ≥15 文件已存在该 IP,增量有限);建议统一改引 env
33. `99bc801` P0-4 偏差报告 — NAS 绝对路径/91G 库坐标/实例号入审计档(无凭据无 IP,记录项)
---
## 六、敏感信息专项结论(窗口内 59 提交全扫)
- **无明文密码/token/密钥泄漏。** LLM api_key 只进 Authorization 头、中文报错只列 env 名不打值;Gitea token 只从 `SANGUO_GITEA_TOKEN` env 读取;QMT 登录密码走 DPAPI→env→内存,never argv/on disk;20 个 docs 提交三扫(password/token/secret/sk-/长 base64/内网坐标)18 个 CLEAN,2 个仅内网拓扑级记录(见 P3-32/33)。
- 两处值得拍板的准敏感项:**模拟资金账号 66639661 硬编码**(P2-18,需确认其永为模拟属性)与 **LLM key 的 docker argv 可见窗口**(P3-25,可改 --env-file 收敛)。
---
## 七、逐提交判定清单
**代码类 39 个**(`●`=有发现,`○`=CLEAN;完整 hash 前缀即可在仓内 `git show` 定位):
| # | hash | 类型 | 判定 |
|---|---|---|---|
| 1 | `7f9b413` | fix(monitor) | ○ 双侧休市表镜像逐字一致+同步测试;仅 logs_stale docstring 未随迁(P3-26) |
| 2 | `1b27226` | fix(factor) | ● m6 守卫有效但契约只补一态(P2-11) |
| 3 | `dbe6623` | feat(factor) | ● P1 已自愈+P2-12/13+P3-14/20 |
| 4 | `b582b70` | fix(factor) | ○ fixture 链式幂等重挂,真治序依赖非盖问题 |
| 5 | `367b4cf` | feat(factor) | ● P3-16/17(判定主干与「同批同 run」宣称核实为真) |
| 6 | `f9914ca` | feat(factor) | ● P3-15(区间口径本身自洽) |
| 7 | `d15653d` | feat(factor) | ● P3-18/19(26.32 有据,衰减告警实际由地板 2.0 主导,计划档自认) |
| 8 | `b24f905` | fix(data) | ○ 休市表经官方公告逐项核实,CI 年更为硬失败 |
| 9 | `dbf57f2` | ops(qmt) | ● P2-18/19+P3-28/29/30/31(5 主件无明文凭据,patch×2 确未回) |
| 10 | `434f7bc` | fix(data) | ● P3-27(守卫本体正确,边界已声明) |
| 11 | `e47dddd` | feat(data) | ● P2-16+P3-23/25(读出口/manifest 两域无穿越面) |
| 12 | `1ea143e` | feat(data) | ● P3-22(三层门/后门约束/exit 映射本体合格) |
| 13 | `65e5c02` | feat(data) | ● **P1-1/2/3** + P3-21/24(两层分诊骨架与优雅停机路径正确) |
| 14 | `8bf935b` | feat(data) | ● P2-15(八类事件+类型去重计数正确) |
| 15 | `7b489d1` | feat(api) | ● P3-5(「默认调用零变化」核实为真) |
| 16 | `eb6475b` | feat(data) | ● P2-14(BudgetStop 机制本身稳,半途丢弃不存在) |
| 17 | `f740999` | fix(factor) | ○ 修复波六项逐一核实有效(arity 表 35 项全对照) |
| 18 | `b35287f` | test(frontend) | ○ 断言与实现一致非空洞 |
| 19 | `403a043` | feat(factor) | ● P2-10(回写主路径正确) |
| 20 | `a1caccf` | feat(factor) | ● P2-9+P3-10/11(Pearson 统计主干正确) |
| 21 | `6251451` | fix(strategy) | ● **P1-5**+P2-17(动量 8+全天候 2 调用点对称完整,全仓无第三处同类前视) |
| 22 | `e06bf6c` | fix(factor) | ● **P1-4**+P3-12(无覆盖风险核实:register 重名 raise) |
| 23 | `ca8673e` | refactor(strategy) | ○ 恰删四个 _ex 副本,HEAD 全仓零残留引用 |
| 24 | `4296b4f` | feat(pipeline) | ● P1 已自愈+P2-6+P3-8 |
| 25 | `13f3124` | feat(pipeline) | ● P2-7+P3 已自愈(max_rounds=3 核实真兜住) |
| 26 | `9389a7b` | feat(pipeline) | ● P2-5(矩阵语义本身正确有测试钉) |
| 27 | `8478f23` | fix(factor) | ○ 校准自洽(6 列和式深 8-9≤12,矛盾消除) |
| 28 | `e3e8ccc` | test(frontend) | ○ stub 语义等价不掩盖真实缺陷 |
| 29 | `7d737a7` | fix(factor) | ○ 修复最小且正确,KeyError 面完全封闭 |
| 30 | `7e93c5b` | feat(factor) | ● P3-9(同构算法主干经复刻验证正确) |
| 31 | `62c7975` | feat(factor) | ● P2-8+P3-13(白名单主干扎实,eval 注入面封死) |
| 32 | `1e3579b` | fix(llm) | ● P2-4(六项修复本体全部核实有效) |
| 33 | `7befde0` | feat(pipeline) | ○ 前端无 XSS 面,busy 态防双击 |
| 34 | `a81e1b6` | feat(pipeline) | ● P2 已自愈×1+P3-7/8(鉴权/503-502 分层核实为真) |
| 35 | `1c5f1ab` | feat(pipeline) | ● P2 已自愈(normalize 真同源可证幂等) |
| 36 | `7a89632` | feat(pipeline) | ● P3-6(SQL 全参数化,CRUD 干净) |
| 37 | `9aa104b` | feat(llm) | ● P2-1/3+P2 已自愈×2+P3-3/4 |
| 38 | `46d76e7` | feat(llm) | ● P2-2/3+P3-1/2 |
| 39 | `5fd2d84` | feat(llm) | ○ 无 key 泄漏,chat_url 语义有测试锚定 |
**纯文档 20 个**:18 个 CLEAN(`bf1fe98`,`2fdb025`,`d8ca4a7`,`56fff3d`,`0007f28`,`a3d5f3e`,`4cf88b4`,`a487192`,`c292dcd`,`03e5c8f`,`4e4679a`,`66679d2`,`a59a0d9`,`7ca6345`,`7ce94ad`,`6f4167f`,`780d0dc`,`c131ae9`);2 个含内网拓扑级记录项(`22b4548` P3-32、`99bc801` P3-33)。
---
## 八、处置优先级建议(只提意见,不执行)
1. **本周内**:漏斗三连 P1-1/2/3 同文件可一刀修(checkpoint 边界统一 + limit 生效或删除 + cap 改每夜总量并记丢弃数);P1-4 在 `register_factor` 前补一行 `precheck_expression`。
2. **需设计拍板**(非纯 bug):P1-5 涨停观察分支——接实时 tick 或正式退役该特性并更新 docstring/回测口径。
3. **近期排期**:P2-16(生产接线补 token 断路或改文档,与 1 联动);P2-11/12 同刀修 manifest fail-soft 四态(缺路径/坏 YAML/非 dict/网络失败)并固化为测试清单——本次 fail-soft 类缺陷三度只修一态(1b27226/1e3579b/P2-16),建议立此清单防再犯。
4. **排期消化**:P2-5/6(状态机与 decompose 两步写的原子性)、P2-15(否定守卫窗口)、P2-1(Retry-After)、P2-9/10(闸门可观测性)、P2-13(开单去重加固)、P2-19(探活灯色语义)。
5. **随手清理**:P3 各项,尤其 P3-24 死代码(`_dump_raw_fail` 留着会误导排障)与 P3-26/29 docstring 失真。
## 九、方法与局限
- 7 簇并行子代理审计 + 主审对 5 条 P1 亲自复读源码复核(corpus_funnel.py/corpus_download.py Ctx/monthly_batch.py/all_weather.py/vnpy utility.py 汇点/momentum_timing.py 守卫),P2/P3 采信子代理读码证据(均含代码摘录,坐标已逐一核对后继变更)。
- 未运行任何测试(只读铁律);AST 边界类结论(P2-8、P3-9/13)经子代理用 stdlib 复刻纯函数实测,非猜测。
- `vnpy_v4.4.0/`、`vnpy_qmt_v0.3.3/`、`venv310/` 第三方/环境目录不在审计范围(eval 汇点作为外部事实引用)。
- 本报告未发现需要立即阻断上线的 P0;但 **P2-16 + P1-2/3 组合意味着漏斗首夜全史回填的 token 成本实际无上界**,若近期要放量跑漏斗,建议先落处置建议第 1、3 条。
---
*审计:claude_dev(ZCode 定时任务,2026-10-03 23:10 触发);报告路径:`/Users/chufeng/.openclaw/sanguo_projects/sanguo_vnpy_v2/audit_20261003_recent2days.md`;全程只读,未修改任何代码与文档。*