From b2da02e40a5c68b43398483fe2a438dfecad8528 Mon Sep 17 00:00:00 2001 From: FinDataHub Date: Fri, 18 Sep 2026 22:53:55 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=AE=B0=E5=BD=95=E7=AC=AC=E4=BA=8C?= =?UTF-8?q?=E6=89=B9/=E7=AC=AC=E4=B8=89=E6=89=B9=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E6=9B=B4=E6=AD=A3=E4=B8=89=E5=A4=84=E4=B8=8D?= =?UTF-8?q?=E5=87=86=E7=A1=AE=E8=A1=A8=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 未解决问题清单:P1-8(门控 reroute)、P1-11(搜索 total)标记为已修; 修正编号混用;追加「本批更正」三章 - 复查报告:补充第二批 6 项闭环 + 两项新修的状态表,并说明两套 P1 编号的对应关系 - 记忆:记录根因、修法、证伪结果,以及三处自我更正与生产实测证据 --- .workbuddy/memory/2026-09-18.md | 58 +++++++++++++++++++++++++ FinDataHub-代码与架构复查-2026-09-17.md | 25 +++++++++++ FinDataHub-未解决问题清单-2026-09-17.md | 36 +++++++++++++-- 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/.workbuddy/memory/2026-09-18.md b/.workbuddy/memory/2026-09-18.md index a36a84c..5bac969 100644 --- a/.workbuddy/memory/2026-09-18.md +++ b/.workbuddy/memory/2026-09-18.md @@ -99,3 +99,61 @@ CI 引用的 7 个路径现已全部在索引中;**CI 前三步本地实跑全 **`grep` 的 `\|` 交替第六次咬人**:本次在 `grep -n "add_argument\|choices\|..."` 上再次返回空。 已经在 MEMORY.md 记过四次,仍未改掉动作习惯。**唯一可靠做法:凡多模式,一律用 Grep 工具(ripgrep); 写 Bash grep 时只允许单一 pattern。** + +--- + +## 第三批(22:40–23:00):P1-8 门控死循环 + P1-11 搜索契约 + +### P1-8 Gate3→Gate2 reroute 不收敛 —— 根因是**职责契约矛盾**,不是级别配置 +- Gate2 的 docstring 明确写「OHLC 关系违反:**WARN(标记但不阻断)**」——这是设计意图; +- Gate3 却把同一违规判为「Gate2 应该已检测但未阻断」并 `reroute_target="gate2_cleaning"`; +- 回传一个**结论恒等、不改数据**的上游,数学上不可能收敛 → reroute 计数累加超 + `max_reroute` → `is_blocked=True` → **整批数据被丢弃不落库**。 +- 实测:3000 行中仅 1 行 `high < max(open,close)` 即触发,日志 `pipeline.step_reroute_limit count=4`。 +- **修法**:Gate3 不再为 OHLC 设 reroute(保留为 warn 级兜底记录); + 新增 `OHLC_SYSTEMIC_RATIO = 0.05`,仅当违规**占比**超阈值(整体损坏而非个别坏点)才 block —— + block 是终态、不参与 reroute,故仍收敛。 +- **重要**:Gate3 是全仓**唯一**设置 `reroute_target` 的地方(用 ripgrep 确认)。 + 修完后 reroute 机制在生产上已不可达(保留为公开 API 供未来 gate 使用)。 + +### ⚠️ 自我更正 1:原先"reroute 分支漏 pop"的说法不准确,该处**不是缺陷** +实测双分支 DAG:`fetch_a`/`gate_a` 与 `fetch_b`/`gate_b`/`tail_b`,令 `gate_a` 上报 reroute 到 `gate_b`, +结果 `fetch_a` 只执行 **1 次**。真实行为是「只有与 reroute 触发步骤**同批**完成的步骤会重复执行」, +而对 reroute 目标的**下游**而言,重复执行正是"重置并重跑"语义所必需——强行补 `pop` 反而会破坏它。 +**代码未改**,报告已作废该表述。 + +### P1-11 搜索 total 契约 +- `total` 原为 `len(all_results)`,受 LIMIT 约束 → 恒等于 `min(limit,50)`。 +- 修法:新增与 data **完全同谓词**的 COUNT 查询;另加 `returned` 字段表示当页行数。 +- 实测:`q=股` 时 total=**63321**,与逐表 SQL 直查完全一致(cls 8577 / wallstreetcn 441 / + sina 13341 / gelonghui 13431 / hotlist 18147 / 10jqka 9384)。修复前为 20。 +- 代价:`LIKE '%q%'` 无法走索引,多一次全表扫描;以正确性换一次扫描。FULLTEXT 提速仍未做。 + +### ⚠️ 自我更正 2:`ACTIVE_TABLES` 不含 `news_flash` +`ACTIVE_TABLES = [news_cls, news_wallstreetcn, news_sina, news_gelonghui, news_hotlist, news_10jqka]`。 +原先用 `news_flash` 的 101,916 行去对比接口 total,是**拿两张不同的表在比**,口径错误。 +正确基准是 63,321。缺陷结论不变(20 vs 63321,差 3166 倍)。 + +### ⚠️ 自我更正 3:`external.py` 无同类问题 +其走 `dal.get_live_news()`,该函数本就实现了正确的 COUNT 模式(`subs, cnts`),返回真实 total。 +原报告称其"同构"属误判。 + +### 部署与验证 +- `gate.py` 与 `public.py` 已同步到部署位并实测: + 部署位代码 `blocked=False`;接口 `total=63321` 与 SQL 直查一致。 +- 回归:core 108 passed(+3)、kuaixun 407 passed(+2),5 条新用例**全部做过证伪**。 +- 提交:`81f6271`。 + +### 意外收获:v1.5.2 自动恢复已在生产实测通过 +臣从 shell 手动 `backend-start` 拉起的后端被工具回收(正是记忆里 `start_new_session` 那条), +App 在 60s 健康检查内检测到并自动恢复,日志出现臣新增的计数文案: +``` +[22:48:13] [ERROR] [NewsFlash] 后端服务异常停止 +[22:48:13] [INFO] [AutoRecovery] 自动恢复 快讯后端服务:进程异常退出(第 1 次尝试,近 60 分钟第 1 次故障) +[22:48:34] [INFO] [AutoRecovery] 快讯后端服务 自动恢复成功 +``` +→ 新代码确实在生产运行,且熔断/告警计数按设计工作。 + +### 顺带:curl 访问本机服务被代理拦截 +`curl http://127.0.0.1:8100/...` 报 `upstream connect failed: Connection refused (os error 61)`, +因会话代理未放行 127.0.0.1。**必须加 `--noproxy '*'`**。 diff --git a/FinDataHub-代码与架构复查-2026-09-17.md b/FinDataHub-代码与架构复查-2026-09-17.md index e2ca888..1b49c3a 100644 --- a/FinDataHub-代码与架构复查-2026-09-17.md +++ b/FinDataHub-代码与架构复查-2026-09-17.md @@ -40,6 +40,31 @@ **未完成项**:P0-4(Pipeline 是否接入日更,需产品决策)、P0-5(凭据轮换需在 Tushare 后台操作)、P0-6(字段类型统一,涉及数据迁移)、P0-7 的正式入库、P1-1/P1-2(门控与管线,因 P0-4 未决而暂缓)、P1-5~P1-8、P2 全部。 +### 第二批(09-18):6 项闭环 + 2 项新修 + +| 项 | 结果 | +|---|---| +| P0-1 部署 | ✅ **已部署 v1.5.2**(逐项核对新包修复标记 + 二进制符号;旧版留 597M 回滚点) | +| P0-3 `dividend` 历史 | ✅ **19 行 → 216,364 行**。根因更深:`ann_date` 是**单日点查询而非区间**,该表结构上就装不下全量;改为按报告期 `end_date` 逐季分页幂等 upsert | +| P0-5 凭据明文 | ✅ 移出 **7 个** plist(原报 5 个,已更正)→ `~/.config/findatahub/env`(0600),全部 LaunchAgent 明文归零 | +| P0-7 版本控制 | ✅ 3 个提交;未跟踪 159→0、core 索引 0→45、App 74/74、CI 前三步实跑全通 | +| P1-10 周/月线脱节 | ✅ 数据补齐(周线→20260911、月线→20260831)+ 银层迁移与分红刷新固化进 `tushare_sync.sh` | +| P1-14 Swift 未编译 | ✅ `swift build --disable-sandbox` 通过并部署 | +| **P1-1** 门控 reroute 不收敛 | ✅ **已修**:Gate3 不再为 OHLC 违规 reroute(回传恒等上游不可能收敛),改 warn;新增 `OHLC_SYSTEMIC_RATIO=0.05` 仅在系统性违规时 block。3 条证伪用例 | +| **P1-6** 搜索 total 契约 | ✅ **已修**:total 取真实命中数(实测 63321 与 SQL 直查一致),新增 `returned` 字段。2 条证伪用例 | + +> 编号说明:本节沿用**本复查报告**的 P1 编号(P1-1=门控 reroute、P1-6=搜索接口); +> `FinDataHub-未解决问题清单` 用的是另一套序号(其 P1-8=门控 reroute、P1-11=搜索接口)。 +> 两处指同一组问题,以文件名区分。 + +**本批三处自我更正**(详见未解决问题清单末章): +① 原称"reroute 分支漏 `pop` 致残留步骤重复执行"——实测不符,该处非缺陷,代码未改; +② 原用 `news_flash` 统计做对比,而该表不在 `ACTIVE_TABLES` 内,口径错误(正确为 63,321 行;差 3,166 倍仍成立); +③ 原称 `external.py` 与搜索接口"同构"——实测其走 `dal.get_live_news()`,本就返回真实 total,无缺陷。 + +**验证方式升级**:本批发现 `swift build` 的失败源于 SwiftPM 自身调用 `sandbox-exec`, +`--disable-sandbox` 即可绕过——原先"只能做语法解析"的降级方案作废。 + --- ## 一、整体评估结论 diff --git a/FinDataHub-未解决问题清单-2026-09-17.md b/FinDataHub-未解决问题清单-2026-09-17.md index 3ecd6b6..8506fdb 100644 --- a/FinDataHub-未解决问题清单-2026-09-17.md +++ b/FinDataHub-未解决问题清单-2026-09-17.md @@ -23,11 +23,15 @@ | P1-10 周/月线脱节 | ✅ **数据补齐**(周线 20260727→20260911、月线 20260731→20260831)+ 调度固化防复发 | | P1-14 Swift 未编译 | ✅ **`swift build --disable-sandbox` 通过**(SwiftPM 自身调 sandbox-exec 才是阻塞点) | +**2026-09-18 23:00 再更新**:P1-8(门控死循环)、P1-11(搜索 total 契约)已完成并部署验证, +详见本节末「本批更正」与各自条目。 + **仍未解决、且仍在造成影响的**: - **P0-6 `trade_date` 同列混存两种格式** —— 2026 年 60%(570,165 行)会被标准范围过滤静默丢弃 - **P0-4 Pipeline/门控不在生产路径** —— 待产品决策,且阻塞 P1-8/P1-9 的排期 - **P0-5 的凭据轮换**(外部动作)、`com.ths.dailyarchive` 需一次登录/重启才恢复加载 -- P1-8 门控死循环、P1-9 双源串源(均已可执行复现)、P1-11/12/13、P2 全部 +- P1-9 双源串源(形态需框架级改造,且其所在管线当前不可达 → 待 P0-4 决策) +- P1-12 去重写连接、P1-13 句柄未关、P2 全部 **优先级总表** @@ -40,10 +44,10 @@ | **P0** | 5 | `trade_date` 同列混存两格式 + 跨库排序规则冲突 | ⬜ **未动(本轮最高剩余风险)** | | **P0** | 6 | 七步 Pipeline/四级门控不在生产路径 | ⬜ 待决策(阻塞 P1-8/P1-9) | | **P0** | 7 | 版本控制失效:核心库未入库、CI 必然失败 | ✅ 已完成(两个提交) | -| P1 | 8 | Gate3→Gate2 reroute 不收敛,整批被阻断 | ⬜ 已可执行复现,待 P0-6 决策后排期 | +| P1 | 8 | Gate3→Gate2 reroute 不收敛,整批被阻断 | ✅ **已修**(含 3 条证伪用例,已同步部署位) | | P1 | 9 | 双源并行共享 `context.df`,分支串源 | ⬜ 已可执行复现,同上 | | P1 | 10 | 清洗层周/月线脱节 + akshare 日更无告警 | ✅ 数据与调度已修;⬜ akshare 源侧落后 14 天的告警仍缺 | -| P1 | 11 | 搜索 `total` 契约失真 + N 表 LIKE 全表扫描 | ⬜ 未动 | +| P1 | 11 | 搜索 `total` 契约失真 | ✅ **已修**(total 真实命中数,实测 63321 与 SQL 直查一致);⬜ FULLTEXT 提速未做 | | P1 | 12 | 去重写入每条新建 4~5 个 MySQL 连接 | ⬜ 未动 | | P1 | 13 | 日志句柄与子进程流未关闭 | ⬜ 未动 | | P1 | 14 | Swift 改动未通过编译验证 | ✅ 已完成 | @@ -479,3 +483,29 @@ mysql -u root -h 127.0.0.1 -e "SELECT 'clean' 库, MIN(trade_date) 最早 FROM f > 本文所有数字均来自本次实测(git 索引查询、MySQL 实库统计、运行中进程与日志、可执行复现脚本)。 > 凭据类证据已脱敏,未记录明文值。 + + +--- + +## 本批更正(臣自身两处表述不准,已在复核中证伪并更正) + +### 更正 1:P1-8 的"附加缺陷"说法不准确 +原报告写"reroute 分支未 `remaining.pop(just_completed)` → 已完成步骤以 degree=0 残留、下一轮重复执行"。 +**实测不符**:构造双分支 DAG 探测(`fetch_a`/`gate_a` 与 `fetch_b`/`gate_b`/`tail_b`, +令 `gate_a` 上报 reroute 到 `gate_b`),结果 `fetch_a` 只执行 **1** 次。 +真实行为是:**只有与 reroute 触发步骤同批完成的步骤会被重复执行**;而对 reroute 目标的 +下游而言,重复执行正是"重置并重跑"语义所必需 —— 若强行补 `pop` 反而会破坏它。 +结论:**该处不是缺陷,代码未改**。原表述已作废。 + +### 更正 2:P1-11 的对比口径错了 +原报告用 `news_flash` 表统计出"真实命中 99,359 行"与接口 `total=20` 对比。 +但 `ACTIVE_TABLES = [news_cls, news_wallstreetcn, news_sina, news_gelonghui, news_hotlist, news_10jqka]` +**并不包含 `news_flash`**,所以那是拿两张不同的表在比。 +正确口径:6 张 ACTIVE_TABLES 同谓词合计 **63,321** 行(逐表:cls 8577 / wallstreetcn 441 / +sina 13341 / gelonghui 13431 / hotlist 18147 / 10jqka 9384)。 +缺陷依然成立且严重(20 vs 63321,差 **3,166 倍**),但原始对比数字作废。 + +### 更正 3:`external.py` 无同类问题 +原报告称 `app/routers/external.py:42` 与搜索接口"同构"。实测其走的是 +`dal.get_live_news()`,该函数本就实现了正确的 `COUNT` 模式(`subs, cnts` 两套子查询), +返回真实 `total`。**该处无缺陷**,属原报告误判。