342 lines
35 KiB
Markdown
342 lines
35 KiB
Markdown
# 最近两天 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`;全程只读,未修改任何代码与文档。*
|