docs: L0 进度 3/12,记录 zstandard 残骸坑与决策 26/27

- STATUS.md:本次任务拆成「第一阶段已完成 / 第二阶段进行中」;
  L0 3/12;测试计数改为 39 passed / 44 skipped;
  下一步里写明 io.py 待修的两处(mkdir 早于校验、缺 Raises)
- docs/04-environment.md 坑 6:conda 升级留下的 *.conda_trash 残骸目录会被
  Python 当成 namespace package 导入成功(__file__ 为 None),
  pandas 3.0 因此抛 ImportError: Can't determine version for zstandard
  直接打断 pd.read_csv;含排查方法与「改名禁用」的修法
- docs/dev/personal-pitfalls.md:条目 3(注解与 docstring 打架)复发 +1
- 决策 26:未实现的算法逐条 skip,禁用模块级 pytestmark
- 决策 27:zstandard 残骸改名禁用,不删不重装
- CHANGELOG:补 load_table/save_table 与 Fixed 段
This commit is contained in:
guzhujushi committed 2026-10-01 23:11:48 +08:00
1 parent b6456d97d8
commit 49fd84a2df
4 files changed
+82 -13

No files matched your search

+31 -10
View File
@@ -4,9 +4,13 @@
## 本次任务
审查并精简 ChatGPT 的建库建议 → 生成骨架文件 → 配置 conda 与 venv 环境 → 初始化 git 仓库 → 接入 Gitea 远端。
**第一阶段(已完成)**:审查并精简 ChatGPT 的建库建议 → 生成骨架文件 →
配置 conda 与 venv 环境 → 初始化 git 仓库 → 接入 Gitea 远端。
两套环境均已建成并通过验证,仓库已推送到 `code.guzhujushi.cn`。
**结论:全部完成。** 两套环境均已建成并通过验证;仓库已推送到 `code.guzhujushi.cn`。
**第二阶段(进行中)**:按 `docs/03-roadmap.md` 的 L0 → L1 顺序**逐个实现函数**,
用户本人写 `src/`、Codex 负责审查 + `tests/`(决策 25)。
当前 3/12:`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`。
## 任务清单
@@ -58,7 +62,7 @@
- [x] 推送通道:公网 22 被防火墙过滤 → 改用 Tailscale(`100.115.86.48:22`),
`~/.ssh/config` 加了一条域名别名,remote 里仍写域名
**E. L0 实现进度(2/12)**
**E. L0 实现进度(3/12)**
- [x] `core/result.py` 的 `Result`
- `__repr__`:单行紧凑;`data` 只给类型与规模,**绝不**整数组打印
(十万级数组的 repr 实测仍 < 200 字符);`success` 恒在
@@ -75,7 +79,14 @@
- `set_seed` 同时调 `np.random.seed`,覆盖 sklearn / statsmodels 走的 numpy 旧全局
(全项目**唯一**碰旧接口的地方,带 `# noqa: NPY002` 与理由)
- 测试:`TestRandom` 共 7 条(可复现、透传、无参跟随、旧全局、np.integer、非法类型、共享推进)
- [ ] 剩余 10 项(11 个函数):`load_table` `clean_missing`
- [x] `data/io.py` 的 `load_table`(+ `save_table`,原属 L1,顺手落地)
- 实现由**用户本人**写(决策 25),Codex 只做审查 + 补测试
- `.csv` / `.xlsx` / `.xls` 按扩展名分派;`.csv` 默认编码探测
utf-8 → utf-8-sig → gbk → gb18030,显式传 `encoding=` 时不再探测
- `na_values` 默认吃下空串 / `NA` / `N/A` / `#N/A` / `null` / `-`
- 不支持的扩展名抛 `ValueError`;文件不存在抛带路径的 `FileNotFoundError`
- 测试:`tests/test_data.py` 由 1 条(且被模块级 skip 掉)扩到 **8 条**
- [ ] 剩余 9 项(10 个函数):`clean_missing`
`detect_outliers` `normalize` `standardize` `describe` `correlation_matrix`
`bootstrap_ci` `monte_carlo` `save_figure`
@@ -83,15 +94,16 @@
| 检查 | venv | conda `mcm-toolkit` |
|---|---|---|
| `pytest` | 31 passed, 45 skipped | 31 passed, 45 skipped |
| `pytest` | **39 passed, 44 skipped** | **39 passed, 44 skipped** |
| `import mcm_toolkit` | 0.0.1 / 16 项 | 0.0.1 / 16 项 |
| `ruff check` | All checks passed | All checks passed |
| `scripts/doctor.ps1` | 跑通 | — |
| SALib / pymoo / pyright | 缺失 | 已装 |
- base 亦已复核:numpy 2.4.6 / scipy 1.18.1 / pandas 3.0.6(与两套环境一致)
- skip 的都是等实现的算法行为测试;通过的 31 条 = 20 条公开 API 契约测试
- skip 的都是等实现的算法行为测试;通过的 39 条 = 20 条公开 API 契约测试
(`tests/test_api_surface.py`)+ 11 条 `core` 行为测试(`tests/test_core.py`)
+ 8 条 `data` 行为测试(`tests/test_data.py`)
- 三个 `.ps1` 通过 PowerShell AST 语法解析
### ⚠️ 需要注意 / 遗留
@@ -101,7 +113,7 @@
只差 Python 补丁号(3.13.9 vs 3.13.15)。详见 `docs/04-environment.md` §5。
- [x] ~~Gitea 远程尚未配置~~ → **已配置并推送完成**,见上面 D 节与决策 19/20。
note:仓库当前是 **Public**(匿名 `git ls-remote` 可读),要改私有去 Gitea 仓库设置。
- [ ] L0 完成 2/12(`Result`、`get_rng`/`set_seed`),其余按 `docs/03-roadmap.md` 的 L0 → L1 顺序推进;
- [ ] L0 完成 **3/12**(`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`),其余按 `docs/03-roadmap.md` 的 L0 → L1 顺序推进;
详情见上面 E 节
- [ ] 本机 `exec_command` 在沙箱模式下**完全不可用**
(`helper_unknown_error: setup refresh had errors`),只有提权
@@ -142,11 +154,20 @@
| 23 | `set_seed` 内部**允许**调用 `np.random.seed`(带 noqa) | sklearn / statsmodels 默认走 numpy 旧全局状态,只记自己的 `_GLOBAL_SEED` 覆盖不到它们,"提交能重跑"就是假的。旧接口在这一个点上不是"取随机数"而是"设种子",性质不同 |
| 24 | `get_rng(None)` **复用同一个模块级生成器**(会推进),不每次新建 | **用户本人提出**,取代 Codex 原来"每次新建 `default_rng(全局种子)`"的写法——那样两个都省略 `random_state` 的函数会抽到完全相同的数。共享单例既保证重跑一致,又让流自然推进 |
| 25 | `src/` 下的实现默认由**用户本人**写,Codex 只改 `tests/` 与 `docs/` | 目标是"一边学一边自己写"。曾出现 Codex 直接落盘 `random.py`、与用户编辑器缓冲区冲突导致保存失败。需要代写时用户会明说 |
| 26 | 未实现的算法用**逐条** `@pytest.mark.skip`,禁用模块级 `pytestmark` | 模块级 skip 会把同文件里**已经写好**的函数一起跳过。本次 `test_data.py` 就这样让 `load_table` 零覆盖,直到有人手动数才被发现 |
| 27 | base 里的 zstandard 残骸目录**改名禁用**,不删除、不重装 | 删掉不可逆;`pip install zstandard` 会给 base 塞一个 conda 记录里根本没有的包,下次 `conda update --all` 又要重新判断。改名后 `import` 变回正常 `ModuleNotFoundError`,pandas 自动跳过 |
## 下一步
1. ~~接入 Gitea~~ **已完成**。以后推送前先确认 Tailscale 在线,然后 `git push`
(细节与换机步骤见 `docs/05-git-workflow.md` §3)。
2. 继续 L0,**下一个:`data/io.py` 的 `load_table`**(`save_table` 属 L1,顺手也可做)。
1. **`data/io.py` 待你修两处**(`src/` 归你,Codex 不代写,见决策 25):
- `save_table` 把 `path.parent.mkdir(parents=True, exist_ok=True)` 放在了**后缀校验之前**,
传个 `.txt` 会先建出一个空目录再抛 `ValueError`。
把校验(后缀 + `isinstance(df, pd.DataFrame)`)挪到 `mkdir` 前面即可。
- 两个函数都缺 `Raises` 段落(`docs/02-architecture.md` §4.7 要求写全);
`load_table` 的返回注解建议从 `Any` 改成 `pd.DataFrame` —— docstring 已经承诺返回 DataFrame,
注解写 `Any` 等于同一个契约写了两遍(`docs/dev/personal-pitfalls.md` 条目 3,本次已复发一次)。
2. 继续 L0,**下一个:`data/clean.py` 的 `clean_missing`**(L0 / A 档,直接能写)。
同文件的 `detect_outliers` 是 **S 档**,要先按 `docs/dev/function-card-template.md`
把函数卡片写出来再动手。
3. 每写完一个函数,在 `examples/` 里加一行最小用法,并更新本文件。
4. L0 跑通后,找一道真题(建议 2025 C)走完整流程,反向沉淀函数。