Skip to content

Latest commit

 

History

History
84 lines (54 loc) · 3.72 KB

File metadata and controls

84 lines (54 loc) · 3.72 KB

参与贡献

欢迎 issue 与 PR。本文只讲这个项目特有的规矩,通用的 git 礼仪不再复述。

开发环境、测试、目录地图见 docs/DEVELOPMENT.md

先读这个:七条红线

docs/ARCHITECTURE.md §10

它们不是风格偏好。每条都对应一类会静默产出错数据的失败——不报错、不崩溃, 只是安静地给出一个看起来合理的错数字。这类 bug 在一个估值工具里是最糟的, 因为用户没有任何线索去怀疑它。

违反红线的 PR 不会被合并,哪怕功能是对的。

这个项目的三条特殊要求

1. 拒绝优于猜测。 数据不足时返回结构化的拒绝理由,不要用默认值、行业均值或 上一期数据填坑。「算不出来」是一个合法且有用的答案;一个基于猜测的数字不是。

2. 降级必须可见。 任何「拿不到理想输入所以退而求其次」的路径都要留痕—— flag、warnings、或结构化日志。静默降级在界面上与「这只股票不支持估值」完全同形, 用户无从分辨。

3. 「没有数据」和「没拿到数据」要分开。 前者是正确且完整的答案(这家公司确实 从没分过红),后者是故障(上游超时了)。混为一谈会让用户对着一只从不分红的股票 反复看到「重试通常能补上」——那是假话,喊多了真降级也没人信。

提 PR 之前

uv run --project backend pytest -q
uv run --project backend ruff check app tests
uv run --project backend lint-imports
npm test --prefix frontend -- --run
npx openspec validate --specs

lint-imports 强制估值层的纯函数契约(不得 import 网络与数据库)。这条是机器检查的, 不靠自觉。

改了估值语义要 bump 版本

backend/app/valuation/version.pyENGINE_VERSION,SemVer,并在同一文件的 CHANGELOG 里写清楚改了什么、为什么。历史快照靠它归因;漏 bump 会让新旧口径的 结果混在一起且无法区分。

改了行为要同步 spec

openspec/specs/ 下是行为的形式定义(MUST / SHALL / SHALL NOT)。判据很简单: 这个改动会不会让某句 MUST 变成假话。会,就改 spec;不会,就不用动。

写测试

后端测试全部离线。 不允许联网——用临时 DuckDB/SQLite 与 monkeypatch。

有两个地方特别容易写出「假绿」测试,都实际发生过:

  • 采集源函数按名字在调用时解析ingest/base._late_bound)。存函数对象会让 monkeypatch.setattr 失效,后果不是测试失败而是测试偷偷发真网络请求—— 断言照过,直到上游哪天挂掉才发现这些用例从来没离线跑过。
  • 断言要落在真正的判据上。 曾有一条超时测试只断言 socket.getdefaulttimeout() == 30,那恒为真,无论被测代码是否真的用了它。

写完一条防回归测试,先把修复注释掉确认它会红,再恢复。

注释与文档

本项目的注释密度高于常规,这是刻意的。规矩是:

注释写「为什么」,不写「是什么」。 代码说得清的不要用注释重复一遍。值得写下来的是 ——为什么不用那个更显然的写法、这个魔数怎么来的、这里踩过什么坑、换一种写法会付出 什么代价。

文档同理:docs/ 分四层,上层链接下层而不复述(见 docs/README.md)。

语言

注释、文档、commit message 正文用中文;标识符、类型名、日志 message 用英文。

许可

提交 PR 即表示你同意你的贡献按 Apache License 2.0 授权。