diff --git a/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md b/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md index b3d0514..af57697 100644 --- a/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md +++ b/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md @@ -413,22 +413,23 @@ FETCHERS 注册表新增两键即自动可被未来 provider MCP server 暴露 ### 18.1 硬约束(用户原话级) 1. **存储全部落 NAS、一律不上 VPS**——「vps承载有压力,之前基本面都放在了nas上,没有放vps,本次 - 也一样」。VPS 零参与:零 schtask、零存储、零采集进程;repo 里进脚本仅为随 NAS 部署管道分发 - (promote --target nas → /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2/,**宿主机 - 直读该路径,不经容器**),VPS 侧永远不会被调度。 -2. **采集进程=NAS 宿主机直跑,不绑定 docker**(用户钦点:「不要和docker绑定,避免docker重启就 - 失败」)。运行时=/volume1/stock/corpus/venv(`python3 -m venv --copies` 自举,DSM 自带 - Python 3.8.12/pip 已实测可用,x86_64;依赖锁 cp38 兼容版 pandas/pyarrow/requests)——容器 - 重启/升级/停用零影响,venv `--copies` 连 DSM 换 Python 也不怕。家宽出口 IP ≠ VPS 公网 IP - (49.232.102.198),与 VPS 侧 ak-daily/ak-events 的东财限流**零冲突**。09-06 实测佐证: - np-listapi/巨潮/东财文章页 ~35 发连续探测自家宽 IP 全成功、零限流。 - **与 sanguo-5m 独立容器方案的差异**(用户问):两者同治「不被主容器重启波及」,但 5m 停在 - docker 家族内(`docker run --rm` 一次性容器,仍依赖 daemon+镜像+tag 不改名,优点=镜像环境 - 完整+版本自动跟随主容器),corpus 按用户指令走到底(零 docker)。5m 当年未走到底是合理的—— - bs_5m_eod.py 依赖面=整个镜像环境(baostock 等),宿主 3.8 venv 装不齐;corpus 脚本依赖面 - 收敛为 3 通用包才有条件零 docker(代价=venv 冻结,版本漂移需手动 pip 对齐,已由 T1 锁版本 - 缓解)。**5m 不迁**:在跑且稳定、迁移需重验 baostock@3.8、没坏不动;但其为存量 docker - 依赖点,NAS docker 套件大升级/镜像重建时需人工盯,届时再评估迁 venv。 + 也一样」。VPS 零参与:零 schtask、零存储、零采集进程;repo 里进脚本随 nas-deploy 到 + `/volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2/`(= 采集容器的 `-v` 只读挂载 `/app`, + 与 5m 同款分发通道),VPS 侧永远不会被调度。 +2. **采集进程=一次性容器,与 sanguo-5m 统一**(用户终拍板 2026-09-06「统一到5min吧」)。方案 + 演进:初版按用户「不要和docker绑定,避免docker重启就失败」设计为宿主机 venv 零 docker; + 验收中用户权衡「不想搞出多种下载方法」,比较两方向后拍板 **corpus 向 5m 的 `docker run --rm` + 模式统一**(反向统一有硬阻塞:5m 写入的 data_backup 库为 03:00 链 root 属主产物,admin venv + 写不进;且需重验 baostock@py3.8、动在跑系统)。**被治的痛点不变**——主容器重启不再杀任务 + (08-22 5m 被 CI 杀三案后的同款根治);**保留的弱依赖**=docker daemon 在跑+镜像 tag 不改名 + (与 5m 同款,已跑一个月实证;daemon 停一天,数据次日自愈)。**两项 corpus 专属改进**:①DSM + 任务以 **admin** 跑(09-06 实测 admin 可执行 docker 命令);②容器加 `--user ` → + 输出文件 admin 属主(root 文件坑不复发),**杀进程=`docker stop sanguo-corpus`**(admin 一条 + 命令)。镜像环境完整+版本自动跟随 CI 部署,零 venv 自举/锁版本/漂移问题。家宽出口 IP ≠ VPS + 公网 IP(49.232.102.198),与 VPS 侧 ak-daily/ak-events 的东财限流**零冲突**。09-06 实测 + 佐证:np-listapi/巨潮/东财文章页 ~35 发连续探测自家宽 IP 全成功、零限流。**统一后全图** + (机器内一种,物理下限):VPS=Windows schtask 家族(数值类)|NAS=DSM→bash wrapper→ + `docker run --rm`(5m+corpus 同款,对外爬取)+sync 链(内部搬运)。 3. **时间带**:全部采集限于 **00:30–17:30**,避开 18:05–23:45 傍晚带(VPS 夜任务密集+家宽使用)。 唯一日窗=每日 06:00 起(见 18.3)。 4. 慢爬纪律:单进程单线程、per-domain 限速+抖动、直连不走代理(Session.trust_env=False,防 @@ -467,9 +468,9 @@ Schema(列名冻结,消费方=factor session 因子加工层,后续 provider fet - **脚本**: `scripts/data_platform/corpus_download.py`(repo 内唯一新文件;单脚本红线同款—— corpus 栈一个入口,类型靠内部注册表,禁再开新脚本)。参数 `--lane daily|backfill`、 `--until HH:MM`(墙钟自停)、`--limit N`(手动冒烟)。 -- **调度**: DSM 任务计划 **sanguo-corpus-daily,每日 06:00 一条,以 admin 身份跑**(先例=现有 - 03:00 同步链 DSM 任务(id=2),宿主机直跑多年零 docker;本设计沿同模式但改 admin 跑,避该链 - root 属主文件坑)。 +- **调度**: DSM 任务计划 **sanguo-corpus-daily,每日 06:00 一条,以 admin 身份跑**,机制=与 + sanguo-5m 完全同款的「bash wrapper → 一次性容器」(wrapper=`/volume1/stock/corpus/ + run_corpus.sh`,宿主文件 CI 不覆盖,改后手动同步——同 5m 的 run_5m.sh 部署纪律)。 **为何 admin 而非统一 root**(用户问):①03:00 链 root 属主文件坑已在案——admin scp 覆盖 root 文件 Permission denied 只能先 rm 再拉;语料库生命周期内 admin 侧操作密集(venv 装包/ 回补盯跑/删错分区/debug),admin 属主=全程零摩擦 ②最小权限:出网慢爬+写文件的进程没必要 @@ -477,10 +478,10 @@ Schema(列名冻结,消费方=factor session 因子加工层,后续 provider fet 的是坏模式。**存量脚本一个都不迁移**(用户问「有必要全改admin吗」:没有——03:00 链等既有 root 任务照旧跑,没坏不动;admin 仅是新建 corpus 任务从第一天的选型;两套并行零冲突:目录 隔离/时间窗错开/部署管道不同,互不碰对方文件)。**admin 权限逐项实测**(2026-09-06): - /volume1/stock 建目录/写/删全通(rwxrwxrwx+ACL,admin 属主);venv `--copies` 在 /volume1 - 建成+stdlib OK+pip user-site 既有;读 admin 家 CI 部署路径无障碍;⚠️坑:venv 建在 **/tmp - 会 Permission denied**(DSM /tmp 特殊限制,且 /tmp 会被清空)——设计本就落 /volume1,勿改 - /tmp。设计内无任何一步需要 root;万一未来例外,人工 sudo/改任务属主是逃生门非设计依赖。 + /volume1/stock 建目录/写/删全通(rwxrwxrwx+ACL,admin 属主);**admin 可执行 docker 命令** + (docker ps 实测通过)→ wrapper/容器/`docker stop` 全程 admin 可运维;读 admin 家 CI 部署 + 路径无障碍(初版 venv 方案及其 /tmp 坑实测,已随「统一到 5m」拍板作废,记录在 git 历史)。 + 设计内无任何一步需要 root;万一未来例外,人工 sudo/改任务属主是逃生门非设计依赖。 **root vs admin 终局论证**(用户问「root 数据不可修改的设计更好吗」):root 属主的「写保护」 是半吊子幻觉——admin 不能覆写 root 文件**但能删**(删看目录权限,/volume1/stock rwxrwxrwx, 03:00 链「先 rm 再拉」workaround 实证),防住原地改防不住删了重建;而 root 跑采集的代价是 @@ -502,10 +503,16 @@ Schema(列名冻结,消费方=factor session 因子加工层,后续 provider fet root 地盘 CI 不覆盖须手动 scp,corpus 脚本走 CI deploy 的 repo 路径,搅进一条任务两头别扭 ③06:00 起跑避开 03:00 链跑道(26G 库同步 IO+家宽带宽),且 00 时档公告(54%)凌晨已入库, 06:00 全吃到;DSM 加一条任务代价≈零,改 root 生产链脚本才是真风险: - `/volume1/stock/corpus/venv/bin/python -X utf8 - /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2/scripts/data_platform/corpus_download.py - --lane daily && 同解释器 --lane backfill --until 17:30` - (两 lane 串行=天然互斥;rc 聚合,任一 lane 失败 log 留痕)。**全程零 docker 依赖**。 + wrapper 内部(同 5m 结构+corpus 两改进): + `/var/packages/Docker/target/usr/bin/docker run --rm --name sanguo-corpus + --user --entrypoint python + -v /volume1/stock:/volume1/stock + -v /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2:/app:ro + sanguo_vnpy_v2:lock-aligned /app/scripts/data_platform/corpus_download.py --lane daily` + 成功后同款第二发 `--lane backfill --until 17:30`(两 lane 串行=天然互斥;rc 聚合,任一 lane + 失败 log 留痕)。**`--name sanguo-corpus`=运维锚点:杀进程=`docker stop sanguo-corpus`(admin + 一条命令);`--user `=输出文件 admin 属主**。镜像 tag 与主容器同源,CI 部署自动 + 跟随;tag 若将来基建重建改名,wrapper 跟着改(与 5m 同款注意事项)。 **断点续传(用户钦点加固,所有 lane 的第一设计原则)**: - 粒度=unit(公告=(stock,year)/新闻=(stock,page)/全文/PDF=单 id),每 unit 一枚 marker(state/ @@ -514,6 +521,15 @@ Schema(列名冻结,消费方=factor session 因子加工层,后续 provider fet - daily lane 幂等可重跑(短窗 id 去重,重复执行零副作用);漏日自愈=公告 T-1~T 两天窗,新闻 recent-100 页面天然覆盖数日缺口(冷门股 100 条跨数月)——某天整个任务没跑,次日一次执行即可 补齐,不依赖专门回补。 +- **从 sanguo-5m 借鉴三件**(用户问「断点续传是否一样/可否互借」后盘点 bs_5m_eod.py):① + **单实例锁**(bs_5m.lock pid 活性检测同款——防 DSM 定时与手动补跑撞车双进程竞写 state, + corpus 原设计缺口,采纳为 state/corpus.lock)②**退出码细分**(对齐 5m 语义并适配: + 0=完成,1=致命,2=限流让路,3=墙钟自停让路——rc 即运维信号)③**state 损坏降级路径** + (5m「state 坏→幂等重头无伤」思想;corpus=marker 坏→该 unit 重拉,append-only+id 去重 + 保证幂等无伤)。**5m 反向无需借鉴改造**:其整片推进粒度粗(半年片 3-4h,中断=整片重拉), + 但回灌已完结、OR REPLACE 幂等无害、每日增量 LOOKBACK=7 独立自愈,改造无未来收益—— + **5m 不做结构性改造**,仅两个顺手项下次动 run_5m.sh 时一并(docker run 加 --name 便于 + 定向 stop;头注释 DSM 时点 19:05→00:05 过时修正),不专门跑。 **daily lane(每日,总 ~4.5h,06:00–10:30 前后)**(06:00 晨窗依据 09-06 实测:深市 600 条公告 发布时刻分布=盘中(09-15时)**0%**(3条)、盘后 15-20 时 46%、**00 时档 54%**(巨潮深夜批处理 @@ -564,10 +580,12 @@ PDF 按可得性实下(404 标 missing 不重试);每源每股记录 first_date 3. **news 回补**: 600519 最早条目落 2023-09±1 月(实测硬顶对齐);depth_summary.json 全量产出。 4. **PDF**: 抽 20 份跨年份可打开(%PDF 魔数+size>0+meta 可反查路径);索引行数=文件数。 5. **边界**: /volume1/stock/corpus 之外零写入;VPS 零改动(git diff 触及面仅 scripts+tests+docs); - 容量闸门演练一次(临时阈值)证明会停;**docker 全停状态下手动触发 corpus-daily 照跑通** - (不绑容器的验收实证)。 -5b. **断点续传**: 回补中途 `kill -9` 采集进程→重启后从未完成 unit 续跑,已完成 unit 零重拉 - (marker 核对);某日整个任务停跑一天→次日单次执行把漏日补齐(T-1~T 窗+recent-100 覆盖)。 + 容量闸门演练一次(临时阈值)证明会停;**主容器 restart(nas-deploy)不影响在跑的 corpus 容器** + (一次性容器与主容器互不相干,5m 已实证同款);手动 `docker stop sanguo-corpus` 即停, + 再触发从断点续跑。 +5b. **断点续传**: 回补中途 `docker stop sanguo-corpus`→重启后从未完成 unit 续跑,已完成 unit + 零重拉(marker 核对);某日整个任务停跑一天→次日单次执行把漏日补齐(T-1~T 窗+recent-100 + 覆盖);**单实例锁实证**:DSM 定时在跑时手动触发→让路退出(退出码=2/3 类),双进程零竞写。 6. **测试**: tests/data_platform/ 新增 CI 测试(fetch 全 mock 零网络)——失败语义/短窗去重/ 两天窗自愈/墙钟自停/unit marker,全套本地绿+CI 绿。 @@ -579,10 +597,11 @@ parquet);月度 compaction(数据量小,YAGNI)。 ### 18.7 实施步骤概要(验收通过后,TDD) -T1 宿主机 venv 自举(`--copies`,锁 cp38 兼容版本 pandas/pyarrow/requests,清华镜像)+连通金丝雀 -(每域 1 发)+目录骨架 → T2 corpus_download.py daily lane 四段+断点续传 state 机制+测试 → -T3 DSM 任务注册(admin 身份,零 docker)+首周人工盯跑 → T4 backfill lane ①② → T5 ③④+容量闸门 -→ T6 验收清单执行+活文档本节补「实施终态」小节。每步一个 commit,标签 **[nas]**(VPS 零触及)。 +T1 wrapper+连通金丝雀(run_corpus.sh 按 5m 同款结构编写;`docker run --rm --user ` 跑通 +镜像 python+每域 1 发出网验证+目录骨架)→ T2 corpus_download.py daily lane 四段+断点续传 +state 机制+单实例锁+测试 → T3 DSM 任务注册(admin 身份)+首周人工盯跑 → T4 backfill lane ①② +→ T5 ③④+容量闸门 → T6 验收清单执行+活文档本节补「实施终态」小节。每步一个 commit,标签 +**[nas]**(VPS 零触及)。 ### 18.8 全局下载方案与存放位置总表(回应「不想搞好几套」——本节=现势唯一完整说明) @@ -606,7 +625,7 @@ daily/weekly/monthly/events 三频率+ak-vintage 自检): | ak-vintage 自检 | VPS | 09:00 | 缺日/错标防线 | vintage_status.json | | NAS sync 链(DSM id=2,root) | NAS | 03:00 | VPS→NAS 副本拉取(7 域) | /volume1/stock/… | | sanguo-5m(DSM id=7,root) | NAS | 00:05 | baostock 5min 增量+全量回补(独立一次性容器 `docker run --rm` 跑 lock-aligned 镜像,08-22 治「CI 重启主容器杀在跑任务」;窗口 2020 起,含退市 5547 只,runner=/volume1/stock/sanguo_5m) | **NAS 副本库 dbbardata('5m')=5m 唯一权威** | -| **sanguo-corpus-daily(DSM,admin)** | **NAS** | **06:00** | **巨潮公告+东财新闻(本设计)** | **/volume1/stock/corpus/** | +| **sanguo-corpus-daily(DSM,admin)** | **NAS** | **06:00** | **巨潮公告+东财新闻(本设计,一次性容器同 5m 模式)** | **/volume1/stock/corpus/** | **存放位置全景**:**数值权威=VPS `data/`**(dbbardata 26G+static/+valuation_baostock/), **两个例外在 NAS**:①**5min——权威=NAS 副本库**`/volume1/stock/sanguo_vnpy_v2/data_backup/